简体   繁体   中英

Some sort of loop to move NULL values to last column in a number of columns?

I'm returning 4 columns in my query, each of which can contain information or be a NULL value. Is there a way to create some sort of loop so that for each row, all the non-NULL values are moved the left most columns with the NULLs at the end? Or perhaps with the use of functions?

My situation:

Value 1 Value 2 Value 3 Value 4
5 3 NULL 1
6 NULL NULL 3

My desired result:

Value 1 Value 2 Value 3 Value 4
5 3 1 NULL
6 3 NULL NULL

Despite the interesting comments, this can be done, probably in most RDMS as long as they support array functions. (There will be variation in how it's done). I made the example table more complicated to show more possible cases.


Schema (PostgreSQL v13)

CREATE TABLE t (
  "value_1" INTEGER,
  "value_2" INTEGER,
  "value_3" INTEGER,
  "value_4" INTEGER
);

INSERT INTO t
  ("value_1", "value_2", "value_3", "value_4")
VALUES
  ('5', '3', null, '1'),
  ('6', null, null, '3'),
  ('3', '2', '1', '0'),
  (null, '2', null, '4'),
  (null, null, '3', '4'),
  (null, '3', '4', '5'),
  (null, null, null, '4');

Query

SELECT all_vals[1] Value_1
     , all_vals[2] Value_2
     , all_vals[3] Value_3
     , all_vals[4] Value_4
FROM (
    SELECT array_remove(ARRAY[value_1, value_2, value_3, value_4], NULL) all_vals
    FROM t
) arrs;
value_1 value_2 value_3 value_4
5 3 1
6 3
3 2 1 0
2 4
3 4
3 4 5
4

View on DB Fiddle


Schema (MySQL v8.0)

CREATE TABLE t (
  `value_1` INTEGER,
  `value_2` INTEGER,
  `value_3` INTEGER,
  `value_4` INTEGER
);

INSERT INTO t
  (`value_1`, `value_2`, `value_3`, `value_4`)
VALUES
  ('5', '3', null, '1'),
  ('6', null, null, '3'),
  ('3', '2', '1', '0'),
  (null, '2', null, '4'),
  (null, null, '3', '4'),
  (null, '3', '4', '5'),
  (null, null, null, '4');

Query

SELECT all_values -> "$[0]" value_1
     , all_values -> "$[1]" value_2
     , all_values -> "$[2]" value_3
     , all_values -> "$[3]" value_4
FROM ( -- The Ordering here matters, as they appear to change the index when removed, so I had to work back to front. 
       -- $[4] (Or any value outside the range) is necessary, as a NULL will cause the whole thing to return NULL.
  SELECT JSON_REMOVE(JSON_ARRAY(value_1, value_2, value_3, value_4) 
                     , CASE WHEN value_4 IS NULL THEN "$[3]" ELSE "$[4]" END
                     , CASE WHEN value_3 IS NULL THEN "$[2]" ELSE "$[4]" END
                     , CASE WHEN value_2 IS NULL THEN "$[1]" ELSE "$[4]" END
                     , CASE WHEN value_1 IS NULL THEN "$[0]" ELSE "$[4]" END
                    ) all_values
  FROM t) arr;
value_1 value_2 value_3 value_4
5 3 1
6 3
3 2 1 0
2 4
3 4
3 4 5
4

View on DB Fiddle

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM