Оператор SQL SELECT с динамическими именами столбцов - PullRequest
2 голосов
/ 03 октября 2019

Я пытаюсь выбрать столбцы, имена которых являются содержимым других столбцов. Я использую MySQL 5.6.

Допустим, у меня есть "table1":

+------+------------+------------+---------------+---------------+
|  id  |  val_int1  |  val_int2  |  val_string1  |  val_string2  |
+------+------------+------------+---------------+---------------+
|  1   |  70        |  88        |  xxx          |  yyy          |
+------+------------+------------+---------------+---------------+

И "table2":

+------+--------+----------+
|  id  |  type  |  ref_id  |
+------+--------+----------+
|  10  |  i1    |  1       |
|  20  |  s2    |  1       |
+------+--------+----------+

Что я хочу сделать, это: объедините table1 и table2, поле table2.type содержит имя столбца из table1, который я хочу выбрать. И еще есть проблема в том, что поле типа содержит только сокращения, которые мне нужно расширить.
Это заканчивается следующим оператором SQL:

SELECT
    t1.id,
    IF(t2.type REGEXP 'i[0-9]+', REPLACE(t2.type, 'i', 'val_int'), REPLACE(t2.type, 's', 'val_string'))
FROM
    table1 t1, table2 t2
WHERE
    t1.id = t2.ref_id AND t1.id = 1

В результате функции REPLACE возвращают значения val_int1 и val_string2. как фиксированные строки, а не обрабатывать его как имена столбцов.

Что я действительно ожидаю, так это:

+-----+-------+
|  1  |  70   |
|  1  |  yyy  |
+-----+-------+

Ответы [ 2 ]

5 голосов
/ 03 октября 2019

Вам нужно какое-то выражение case:

select t1.id,
       (case when t2.type = 'i1' then cast(val_int_1 as varchar(255))
             when t2.type = 'i2' then cast(val_int_2 as varchar(255))
             when t2.type = 's1' then val_string_1
             when t2.type = 's2' then val_string_2
        end) as val
from table1 t1 cross join
     table2 t2;

Вы, вероятно, будете жаловаться "о, у меня так много столбцов". В принципе тоже неплохо. У вас плохой дизайн базы данных. Вы пытаетесь выполнить частичное сопоставление имен строк и столбцов. Даже решение с динамическим SQL не очень выполнимо.

0 голосов
/ 03 октября 2019

Используя выражение для случая, вот как я бы решил это:

DECLARE @table1 TABLE
(
    id INT,
    val_int1 INT,
    val_int2 INT,
    val_string1 NVARCHAR(100),
    val_string2 NVARCHAR(100)
)

INSERT INTO @table1 VALUES
(1,70,88,'xxx','yyy')

DECLARE @table2 TABLE
(
    id INT,
    type NVARCHAR(MAX),
    ref_id INT
)

INSERT INTO @table2 VALUES
(10,'i1',1),
(20,'s2',1)

SELECT 
    id,
    CASE WHEN type = 'i1' THEN CAST((SELECT TOP 1 val_int1 FROM @table1) AS NVARCHAR(100)) ELSE 
        CASE WHEN type = 'i2' THEN CAST((SELECT TOP 1 val_int2 FROM @table1) AS NVARCHAR(100)) ELSE 
        CASE WHEN type = 's1' THEN (SELECT TOP 1 val_string1 FROM @table1) ELSE 
            (SELECT TOP 1 val_string2 FROM @table1) END END END
FROM @table2 t2

ВЫХОД:

10  70
20  yyy
...