SQLITE Query- To retrieve all versions between two versions?

最后都变了- 提交于 2019-12-23 07:04:57

问题


The sqlite table consists of attributes :

|Versions (TEXT)|
| "2.73.8"      | 
| "3.6.4 "      | 
| "3.9.11"      | 

and so on..

I want to retrieve all the versions from the table between two versions given in the query. For instance: Between versions- 2.9.10 & 3.7.10 .

I could not find any sqlite function to query this directly. I used Substring (SUBSTR) to split to get individual digits which could then be compared to the one present in the table. I was successful in doing that but I could find a way to query to retrieve all versions between two version set.

create table prod(version varchar);

insert into prod values('2.7.5');
insert into prod values('2.7.4');
insert into prod values('2.0.0');
insert into prod values('22.73.55');
insert into prod values('22.17.54');
insert into prod values('22.10.06');
insert into prod values('3.7.5');
insert into prod values('3.4.5');
insert into prod values('3.7.6');

Query to retrieve all versions below or equal to : "3.50.6" (using nested "case when" ):



SELECT * from prod
Where version IN ( SELECT 
    CASE WHEN (CAST(substr(version,0,instr(version,'.')) as integer)=3)
         THEN 
            CASE WHEN (cast(SUBSTR(SUBSTR(version, INSTR(version, '.')),1,INSTR(SUBSTR(version, INSTR(version, '.') + 1), '.') - 1) as float)< 0.50 )
                 THEN
                    version
                 ELSE
                    CASE WHEN (cast(SUBSTR(SUBSTR(version, INSTR(version, '.')),1,INSTR(SUBSTR(version, INSTR(version, '.') + 1), '.') - 1) as float)=0.50)
                         THEN
                             CASE WHEN (CAST(replace(version, rtrim(version, replace(version, '.', '')), '')AS INTEGER)<=6)
                                  THEN version

END  END END END FROM prod);


Kindly provide me a way to query to retrieve all versions in the table between two sets of versions.


回答1:


I believe the following will do as you want :-

WITH 
  /* SELECTION parameters */
  parm(p1,p2) AS (SELECT '3.4.5', '22.10.6' /*<<<<<<<<<<<<< Versions to check against lower first*/),
    /* Parse 1, 1st value of each and the rest for parse2 */
    pv1(parmv1,rest4p2,parm2v1,rest4p22) AS (
        SELECT 
            CAST(substr(p1,1,instr(p1,'.')-1) AS INTEGER),
            substr(p1,instr(p1,'.')+1), 
            CAST(substr(p2,1,instr(p2,'.')-1) AS INTEGER),
          substr(p2,instr(p2,'.')+1)    
        FROM parm
        ),
    /* Parse 2 extra 2 values retrieved for each parameter */
    pv2(parmv2,parmv3,parm2v2,parm2v3) AS (
        SELECT 
            CAST(substr(rest4p2,1,instr(rest4p2,'.')-1) AS INTEGER),
            CAST(substr(rest4p2,instr(rest4p2,'.')+1) AS INTEGER),
            CAST(substr(rest4p22,1,instr(rest4p22,'.')-1) AS INTEGER),
            CAST(substr(rest4p22,instr(rest4p22,'.')+1) AS INTEGER)
    FROM pv1),
    /* calculate the lower and upper values to be checked against for the BETWEEN clause */
    finalp(lower,higher) AS (
        SELECT 
            (parmv1 * 1000 * 1000) + (SELECT (parmv2 * 1000) + parmv3 FROM pv2),
            (parm2v1 * 1000 * 1000) + (SELECT (parm2v2 * 1000) + parm2v3 FROM pv2) 
        FROM pv1),

    /* Parse 1 for the actual data gets the 1st part of the version and the rest of the version */  
    v1(v1rowid,vpart1,rest4v2) AS (SELECT rowid, CAST(substr(version,1,instr(version,'.')-1) AS INTEGER),substr(version,instr(version,'.')+1)  FROM prod),
    /* Parse 2 for the actual data gets the 2nd and third parts */
    v2(v2rowid,vpart2,vpart3) AS (SELECT v1rowid, CAST(substr(rest4v2,1,instr(rest4v2,'.')+1) AS INTEGER),CAST(substr(rest4v2,instr(rest4v2,'.')+1) AS INTEGER) FROM v1)

SELECT version
FROM v1 
    JOIN v2 ON v1rowid = v2rowid /* join the 2nd and third parts with the 1st */
    JOIN prod ON prod.rowid = v1rowid /* also join the original data for the original version */ 
    JOIN finalp ON 1 = 1 /* joint the upper and lower values */
WHERE 
    (vpart1 * 1000 * 1000) + (vpart2 * 1000) + vpart3 /* do the same calculation used for the upper and lower parameters */ 
    BETWEEN lower AND higher
; 

The above results in :-

and using :-

.... (SELECT '3.4.5', '22.10.06' /*<<<<<<<<<<<<< Versions to check against lower first*/) ...

as well as :-

.... (SELECT '3.4.5', '22.10.6' /*<<<<<<<<<<<<< Versions to check against lower first*/) ....

- .6 instead of .06 (i.e. leading 0's are ignored)

Results in :-

  • This also checks boundary hits i.e. 3.4.5 and 20.10.06 were selected.



回答2:


I assume that each one of the 3 parts of the version value is max 3 digits.
The simplest way to convert a version value to a number so to make it comparable, is : multiply the 1st part by 1000000, the 2nd part by 1000 and then add them plus the 3d part.
In code:

1000000 * replace(version, '.', 'x') +
1000 * replace(substr(version, instr(version, '.') + 1), '.', 'x') +
replace(version, '.', '000') % 1000 number

If you execute:

select 
  version,
  1000000 * replace(version, '.', 'x') +
  1000 * replace(substr(version, instr(version, '.') + 1), '.', 'x') +
  replace(version, '.', '000') % 1000 numericversion
from prod

you get:

| version  | numericversion  |
| -------- | --------------  |
| 2.7.5    |  2007005        |
| 2.7.4    |  2007004        |
| 2.0.0    |  2000000        |
| 22.73.55 | 22073055        |
| 22.17.54 | 22017054        |
| 22.10.06 | 22010006        |
| 3.7.5    |  3007005        |
| 3.4.5    |  3004005        |
| 3.7.6    |  3007006        |

So to get all versions between versions- 2.9.10 & 3.7.10, do this:

with 
  cte1 as (
    select
      1000000 * replace('2.9.10', '.', 'x') +
      1000 * replace(substr('2.9.10', instr('2.9.10', '.') + 1), '.', 'x') +
      replace('2.9.10', '.', '000') % 1000 numericversion  
  ),
  cte2 as (
    select
      1000000 * replace('3.7.10', '.', 'x') +
      1000 * replace(substr('3.7.10', instr('3.7.10', '.') + 1), '.', 'x') +
      replace('3.7.10', '.', '000') % 1000 numericversion  
  ),
  versions as (
    select 
      version, 
      1000000 * replace(version, '.', 'x') +
      1000 * replace(substr(version, instr(version, '.') + 1), '.', 'x') +
      replace(version, '.', '000') % 1000 numericversion
    from prod  
  )  
select version from versions
where numericversion between 
  (select numericversion from cte1) and (select numericversion from cte2)

The 1st CTE returns the numeric value of 2.9.10, the 2nd CTE returns the numeric value of 3.7.10 and the 3d the numeric values of all the versions in the table.
Finally the query compares the numeric versions.
See the demo.
Results:

| version |
| ------- |
| 3.7.5   |
| 3.4.5   |
| 3.7.6   |

Or without the CTEs by hardcoding the 2 versions as numbers:

select version from prod
where 
  1000000 * replace(version, '.', 'x') +
  1000 * replace(substr(version, instr(version, '.') + 1), '.', 'x') +
  replace(version, '.', '000') % 1000 
  between 2009010 and 3007010

See the demo.
Or:

select version from prod
where 
  1000000 * replace(version, '.', 'x') +
  1000 * replace(substr(version, instr(version, '.') + 1), '.', 'x') +
  replace(version, '.', '000') % 1000 
  between 
    1000000 * replace('2.9.10', '.', 'x') +
    1000 * replace(substr('2.9.10', instr('2.9.10', '.') + 1), '.', 'x') +
    replace('2.9.10', '.', '000') % 1000
    and
    1000000 * replace('3.7.10', '.', 'x') +
    1000 * replace(substr('3.7.10', instr('3.7.10', '.') + 1), '.', 'x') +
    replace('3.7.10', '.', '000') % 1000 

See the demo.



来源:https://stackoverflow.com/questions/57049677/sqlite-query-to-retrieve-all-versions-between-two-versions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!