У меня есть три столбца X, Y и Z. Я хочу сделать оператор выбора, который возвращает только один столбец. Например, для следующих строк:

X Y Z
1 0 0 
0 1 0
0 0 1

Я хочу вернуть один столбец A:

A
X 
Y
Z

Таким образом, где бы он ни был, столбец должен возвращать строку, соответствующую имени столбца, где он один.

У меня нет прав на создание нового столбца в базе данных, а затем обновить его, используя условие where. Поэтому мне было интересно, если это можно сделать внутри инструкции SELECT

sql
0
Julius Knafl 5 Мар 2018 в 15:41

4 ответа

Лучший ответ

Без работы с несколькими 1 значениями в одной строке:

select case
         when x = 1 then 'X' 
         when y = 1 then 'Y'
         when z = 1 then 'Z'
       end as A
from the_table;

Если вы используете Postgres и у вас есть столбец первичного ключа в этой таблице, вы можете использовать функции JSON, чтобы сделать это динамическим, а не жестко кодировать имена столбцов в запросе.

Настройка тестовых данных:

create table the_table (id integer, x int, y int, z int);
insert into the_table 
  (id,x,y,z)
values
  (1, 1, 0, 0), 
  (2, 0, 1, 0),
  (3, 0, 0, 1),
  (4, 0, 1, 1),
  (5, 0, 0, 0);

Затем с помощью этого запроса:

select t.id, string_agg(k.col,'' order by k.col) as non_zero_columns
from the_table t, 
     jsonb_each(to_jsonb(t) - 'id') as k (col, val)
where k.val = '1'
group by id
order by id;

Вернет этот результат:

id | non_zero_columns
---+-----------------
 1 | x               
 2 | y               
 3 | z               
 4 | yz              

Обратите внимание, что строка с ID = 5 не возвращается, поскольку все столбцы равны нулю.

3
a_horse_with_no_name 5 Мар 2018 в 13:52

Если у вас есть несколько столбцов с 1 в одной строке:

select ((case when x = 1 then 'X' else '' end) ||
        (case when y = 1 then 'Y' else '' end) ||
        (case when z = 1 then 'Z' else '' end)
       ) as A
from the_table;

Обратите внимание, что || является стандартным оператором ANSI для конкатенации строк. Некоторые базы данных используют другие методы для объединения строк.

1
Gordon Linoff 5 Мар 2018 в 13:24

Вы можете использовать INFORMATION_SCHEMA с find_in_set(str, strlist) (MySql ) :

-- the schema
create table `docs` (
  `X` int not null,
  `Y` int not null,
  `Z` int not null
);
insert into `docs` (`X`, `Y`, `Z`) values
  (1, 0, 0),
  (0, 1, 0),
  (0, 0, 1);

-- the query
select column_name as A, concat(x, y, z)
from docs
join INFORMATION_SCHEMA.COLUMNS
on (ordinal_position = find_in_set('1', concat(x, ',', y, ',', z)))
where table_name like 'docs';

Здесь SQL Fiddle

-1
thibsc 5 Мар 2018 в 13:42

Если вы используете ms sql-сервер, вы можете использовать UNPIVOT

DECLARE @MyTable TABLE (X INT, Y INT, Z INT)
INSERT INTO @MyTable VALUES
(1 ,0, 0 ),
(0 ,1, 0 ),
(0 ,0, 1 )

SELECT DISTINCT A FROM 
    (select * from @MyTable UNPIVOT( V FOR A IN ([X], [Y], [Z])) UNPVT) UP
WHERE V = 1

Результат:

A
---------
X
Y
Z
0
Serkan Arslan 5 Мар 2018 в 13:36