Home > Back-end >  Update rows based on range around values without changing rows that are not initially within range
Update rows based on range around values without changing rows that are not initially within range

Time:09-17

In a local SQLite (vs 3.29.0) database, there is a table with 3 columns (excluding the rowID). Two contain values, and one contains categories. I want to update the category based on a range around the values of one specific category. It needs to be possible that the category that is SET is the same category as the one that determines the range.

Example:

id Value Value2 Category
1 20 20 2
2 30 30 2
3 40 40 2
4 70 70 2
5 5 5 1
6 19 19 1
7 26 26 1
8 42 42 1
9 49 49 1
10 52 52 1
11 71 71 1
12 90 90 1
13 17 17 1

I want rows to be changed to category 2, based on a range of 4 around value and a range of 2 around value2. This should change only rows 6, 9 and 11:

id Value Value2 Category
1 20 20 2
2 30 30 2
3 40 40 2
4 70 70 2
5 5 5 1
6 19 19 2
7 26 26 1
8 42 42 2
9 49 49 1
10 52 52 1
11 71 71 2
12 90 90 1
13 17 17 1

My current SQL statement is:

UPDATE tablename
SET Category = 2
WHERE (Category != 2
  AND EXISTS (
        SELECT *
        FROM tablename t
        WHERE t.Category = 2
          AND tablename.Value BETWEEN t.Value - 4 AND t.Value   4
          AND tablename.Value2 BETWEEN t.Value2 -2 AND t.Value2  2)
          );

of which the result is:

id Value Value2 Category
1 20 20 2
2 30 30 2
3 40 40 2
4 70 70 2
5 5 5 1
6 19 19 2
7 26 26 1
8 42 42 2
9 49 49 1
10 52 52 1
11 71 71 2
12 90 90 1
13 17 17 2

What appears to be happening is that due to row 6 changing to category 2, row 13 is now within range of the values of a row that is in category 2, and therefore is also assigned category 2. How do I change the statement so that the SET is only applied to the values that were within range initially?

See the demo for the example.

CodePudding user response:

If your version of SQLite is 3.33.0 you can use the join-like UPDATE...FROM syntax to perform a self join in the UPDATE statement:

UPDATE tablename AS t1
SET Category = t2.Category
FROM tablename AS t2 
WHERE t2.Category = 2
  AND t1.Category <> t2.Category
  AND t1.Value BETWEEN t2.Value - 4 AND t2.Value   4
  AND t1.Value2 BETWEEN t2.Value2 - 2 AND t2.Value2   2;

For previous versions of SQLite, first create a temporary table with all the rows of the table with Category = 2:

CREATE TEMPORARY TABLE t AS 
SELECT * FROM tablename WHERE Category = 2;

and then update the table:

UPDATE tablename
SET Category = 2
WHERE Category <> 2
  AND EXISTS (
        SELECT 1
        FROM t
        WHERE tablename.Value BETWEEN t.Value - 4 AND t.Value   4
          AND tablename.Value2 BETWEEN t.Value2 -2 AND t.Value2   2
      );

See the demo.

  • Related