用JAVA實現插值查詢的方法(算近似值,區間求法)


插值查詢:如果有這樣一張表,有一列叫水位,有一列叫庫容,比如下面的圖。

 

我現在想做這么一件事情:對於這個測站而言,當我輸入某一個水位或者庫容的時候,想要查詢到對應的水位或者庫容呢?

而這個值不一定是存在數據庫中的,也許這只是一個推導出來的近似值呢?

算法要點:如果這個輸入的值是位於數據庫值的某一個區間內的話,那么取最小的區間,然后求這個區間內單位數量的值。

大家聽得可能有點不太明白,我畫張圖。

呵呵,應該有點眉目了吧?這個第一步也是最重要的一步就是確定區間哦

算法的話很簡單,用一句公式來概括就是

1.通過水位求庫容:(單位水位所包含的庫容)*(輸入水位-這個水位左邊區間的水位值)+這個水位左邊區間的水位值

2.通過庫容求水位:(單位庫容所包含的庫容)*(輸入庫容-這個庫容左邊區間的庫容值)+這個庫容左邊區間的庫容值

 

不廢話,貼代碼,用的是JAVA實現的

    //插值查詢法
        @Override
        public String InterpolantQuery(ReservoirCapacityConditionParam param)
        {
            String finalVal="";
            float finalVolumn=0;
            StringBuffer sb=new StringBuffer();
            StringBuffer sd=new StringBuffer();
            sb.append("select z,v from hydro_curve_b where stcd='"+param.getStcd()+"' ");
            
            if(param.getV()==""&&param.getZ()!="")
            {
                sb.append(" and z='"+param.getZ()+"'");
            }
            else if(param.getV()!=""&&param.getZ()=="")
            {
                sb.append(" and v='"+param.getV()+"'");
            }
            
            List<Object []> fromSTCD=this.daoHelper.findBySql(sb.toString());
            
            //如果是已有數據,直接顯示,否則算法查找
            /*算法:通過庫容查水位或通過水位查庫容,如果輸入的值在已有數據的某個范圍內,則定位此數據的最小范圍
             * 1.比如輸入120,有119~121,118~122這2個范圍,則取119~121這個近似范圍
             * 2.假設輸入的是水位,要查詢庫容,那么首先算出每一米水位在(1)范圍內的庫容,然后算出庫容的增量,用這個增量加上這個區間內較低的庫容
             * 3.由於框架不能使用TOP關鍵字,所以(1)的范圍的的取法:左邊:查出比輸入值小的所有數據,按大小的降序拍了,取最后一條,右邊:查出比輸入值大的所有數據,按升序排列,取最后一條*/
            if(fromSTCD.size()==0)
            {
                //如果水位為空,則按照庫容查詢水位
                if(param.getZ()=="")
                {
                
                    if(param.getV().equals("0"))
                    {
                        //如果輸入0,則不查詢
                    }
                    
                    else
                    {
                        //查出左邊區間的
                        List<Object []> left_fromSTCD=this.daoHelper.findBySql("select  z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and v<'"+param.getV()+"' order by z asc");

                        //查出右邊區間的
                        List<Object []> right_fromSTCD=this.daoHelper.findBySql("select  z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and v>'"+param.getV()+"' order by z desc");
                        
                        float beginZ=0,beginV=0; //水位
                        float endZ=0,endV=0;     //庫容
                        
                        //如果左邊區間為空
                        if(left_fromSTCD.size()==0)
                        {
                            //重置左邊的區間
                            left_fromSTCD=this.daoHelper.findBySql(" select z,min(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' group by z order by z desc");
                            
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                            
                            //重置右邊的區間
                            right_fromSTCD=this.daoHelper.findBySql("select z.* from (select  top 2 z,min(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' and  v>"+param.getV()+" group by z) z order by z.z asc");
                            
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        
                        else
                        {    
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        
                        //如果右邊區間為空
                        if(right_fromSTCD.size()==0)
                        {
                            //重置左邊的區間
                            left_fromSTCD=this.daoHelper.findBySql("select z.* from (select  top 2 z,max(v) v from hydro_curve_b where stcd='"+param.getStcd()+"' and v<"+param.getV()+" group by z) z order by z.z desc");
                            
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                            
                            //重置右邊的區間
                            right_fromSTCD=this.daoHelper.findBySql("select z,max(v) from hydro_curve_b where stcd='"+param.getStcd()+"' group by z order by z asc");
                            
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        else
                        {    
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                
                        //計算每一格庫容所包含的水位
                        float eachVolumn=1/((endV-beginV)/(endZ-beginZ));
                        float z=Float.parseFloat(param.getV());
                        //得到最終的水位
                        finalVolumn=(z-beginV)*eachVolumn+beginZ;
                    }
                
                
                
                }
                //如果庫容為空,則按照水位查詢庫容
                else if(param.getV()=="")
                {
                    
                    if(param.getZ().equals("0"))
                    {
                        //如果輸入0,則不做任何操作
                    }
                    else
                    {
                        //查出左邊區間的
                        List<Object []> left_fromSTCD=this.daoHelper.findBySql("select  z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z<'"+param.getZ()+"' order by v asc");

                        //查出右邊區間的
                        List<Object []> right_fromSTCD=this.daoHelper.findBySql("select  z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z>'"+param.getZ()+"' order by v desc");
                        
                        float beginZ=0,beginV=0; //水位,庫容(left)
                        float endZ=0,endV=0;     //水位,庫容(right)
                        
                        //如果輸入的最小值比最數據庫里的最小值小,那么取數據庫里的最小值
                        //重置區間的原因是因為最小值是一個區間,用TOP2確定范圍
                        if(left_fromSTCD.size()==0)
                        {
                            //重置左邊的區間
                            left_fromSTCD=this.daoHelper.findBySql(" select MIN(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' group by v order by v desc");
                            
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                            
                            //重置右邊的區間
                            right_fromSTCD=this.daoHelper.findBySql("select z.* from (select  top 2 min(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and  z>"+param.getZ()+" group by v) z order by z.v asc");
                            
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        else
                        {    
                
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        //如果輸入的最大值比數據庫里的最大值大,那么取數據庫的最大值。
                        if(right_fromSTCD.size()==0)
                        {
                            
                            //重置左邊的區間
                            left_fromSTCD=this.daoHelper.findBySql("select z.* from (select  top 2 max(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' and z<"+param.getZ()+" group by v) z order by z.v desc");
                            
                            for(Object []obj:left_fromSTCD)
                            {
                                beginZ=Float.parseFloat(String.valueOf(obj[0]));
                                beginV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                            
                            //重置右邊的區間
                            right_fromSTCD=this.daoHelper.findBySql("select max(z) z,v from hydro_curve_b where stcd='"+param.getStcd()+"' group by v order by v asc");
                            
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }

                        }
                            
                        else
                        {    
                            for(Object []obj:right_fromSTCD)
                            {
                                endZ=Float.parseFloat(String.valueOf(obj[0]));
                                endV=Float.parseFloat(String.valueOf(obj[1]));
                            }
                        }
                        //計算每一格庫容所包含的水位
                        //float eachVolumn=(endV-beginV)/(endZ-beginZ);
                        float eachVolumn=1/((endZ-beginZ)/(endV-beginV));
                        float z=Float.parseFloat(param.getZ());
                        //得到最終的庫容
                        //finalVolumn=(endZ-z)*eachVolumn+endZ;
                        finalVolumn=beginV+eachVolumn*(z-beginZ);
                        
                    }
                    
                    
                }
                        
                return String.valueOf(finalVolumn);
    
                
            }
            else
            {
                for(Object obj[]:fromSTCD)
                {
                    if(param.getV()=="")
                    {
                    finalVal=String.valueOf(obj[1]);
                    }
                    else if(param.getZ()=="")
                    {
                        finalVal=String.valueOf(obj[0]);
                    }
                    
                }
                return finalVal;
            }
            
            
        }

其中也沒什么難點,就是要注意一下左右區間重置的計算方法。

因為每次FOR遍歷出里面的變量以后,前面的變量都會被后面的變量所覆蓋,所以這里大家需要注意一下,合理使用top關鍵字和order by 是做出這個的關鍵,

好了,最后截圖2張給大家看看效果,最后啰嗦一句,插值查詢法雖然是算出來的,但是和數據庫里的數據時息息相關的,是根據數據庫里的數據算出的近似值。

比如下面的圖,都是輸入200的水位,但是結果不同,因為他們對應的區間不同。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM