Можете ли вы выбрать все, кроме 1 или 2 полей, без писательской судороги? - PullRequest
45 голосов
/ 03 февраля 2012

Возможно ли в PLSQL выбрать все поля в таблице, кроме 1 или 2, без необходимости указывать нужные поля?

Например, таблица сотрудника имеет поля:

  • id
  • имя
  • фамилия
  • хобби

Возможно ли написать запрос, аналогичный

select * from employee

при выходе с поля hobbies без необходимости писать что-то подобное?

select id, firstname, lastname from employee

Ответы [ 11 ]

43 голосов
/ 03 февраля 2012
38 голосов
/ 03 февраля 2012

Если вы хотите избежать спада писателя, вы можете использовать SQL Developer и заставить его сгенерировать список столбцов для вас:

select column_name||','
from all_tab_columns
where table_name = 'YourTableName'

А затем просто уберите один или два столбца, которые вы не указалиt хотите.

Вы также можете использовать

SELECT listagg(column_name, ',') within group (order by column_name) columns
FROM all_tab_columns
WHERE table_name = 'TABLE_NAME'
GROUP BY table_name;
19 голосов
/ 20 октября 2015

Работаете ли вы на Oracle 12c?

Если это так, подумайте, соответствует ли это вашим потребностям:

alter table mytable modify column undesired_col_name INVISIBLE;

В этом случае столбец undesired_col_name будет полностью применим, но он будет исключен из любых операторов SELECT * и т. П. (Например, %ROWTYPE), как если бы он не существовал.

17 голосов
/ 19 октября 2015

Старый поток, но, да ... в Oracle есть способ сделать это:

with

employee(id, firstname, lastname, hobbies) as
(
  select 1, 'a', 'b', '1' from dual union 
  select 2, 'a', 'b', '2' from dual union 
  select 3, 'a', 'b', '3' from dual union 
  select 4, 'c', 'd', '3' from dual union 
  select 5, 'e', 'f', '2' from dual  
)

select * 
from employee 
pivot
( 
  max(1) -- fake  
  for (hobbies) -- put the undesired columns here
  IN () -- no values here...
) 
where 1=1 -- and your filters here...
order by id

Чтобы понять, как работает PIVOT и почему он решает вопрос, давайте рассмотрим лучший пример для нашей таблицы employee:

select * 
from employee 
pivot
(
  max(id) foo,
  max(1)  bar
  for (hobbies) 
  IN ('2' as two, '3' as three)
)

Результат здесь:

FIRSTNAME | LASTNAME | TWO_FOO | TWO_BAR | THREE_FOO | THREE_BAR
    c          d         null      null        4           1
    e          f           5        1         null        null
    a          b           2        1          3           1

Точно такой же вывод можно получить с помощью этого более простого для понимания запроса:

select 
  firstname,
  lastname,
  max(case when hobbies = '2' then id end) two_foo,
  max(case when hobbies = '2' then 1  end) two_bar,
  max(case when hobbies = '3' then id end) three_foo,
  max(case when hobbies = '3' then 1  end) three_bar
from employee 
group by
  firstname,
  lastname

Таким образом, столбец hobbies никогда не выбирается, как столбец id, оба указаны в предложении PIVOT . Все остальные столбцы сгруппированы и выделены.

Что касается первого запроса, он работает по двум причинам:
1- вы не потеряете ни одной строки в процессе группировки, поскольку столбец id является уникальным и столбцы для агрегатов не указаны;
2 - поскольку сводная система генерирует N * M новых столбцов, где N = количество значений предложения IN и M = количество указанных агрегаций, поэтому отсутствие фильтров и единственная безвредная агрегация приведут к 0 * 1 = 0 новых столбцов и удалит те, которые указаны в предложении PIVOT , которое является просто хобби .


ОТВЕТЬТЕ НА КОММЕНТАРИЙ 1

Первая строка этого вопроса гласит: "... без указания нужных полей" . Во всех остальных ответах предложенные запросы указывают нужные поля в предложении SELECT , за исключением моего, фактически.

Также в названии вопроса написано "... без писательской спазма" . Ну, как правильно определить судьбу писателя? Я приложил бы все усилия, чтобы предвидеть хороший стандарт SQL для этой проблемы и сравнить с моим ответом. На самом деле, я думаю, что этот «стандарт» может выглядеть примерно так: SELECT * NOT IN ([col1], [col2], ...) .

Теперь я могу видеть в обоих запросах:

  • список нежелательных столбцов;
  • и IN предложение;
  • предложение из трех символов - FOR и NOT ;

Это означает, что вам нужно написать немного больше в моем подходе, так как вам нужно поддельное агрегирование и предложение PIVOT ... но на самом деле это всего лишь несколько символов ...

2 голосов
/ 29 марта 2017

ОП ищет что-то вроде:

SELECT * MINUS hobbies from...

Лучшее, что нужно сделать, чтобы избежать много печатания (и получить все имена столбцов правильно), - это открыть описание таблицы, вырезать и вставить все имена столбцов и удалить те, которые вам не нужны, запятую отделяйте оставшиеся и поместите их в одну или две строки.

Это просто, быстро, точно, и вы не будете путать следующего человека, который должен работать над вашим кодом.

2 голосов
/ 04 февраля 2012

query_generator - это функция PL / SQL, которая возвращает строку выбора для таблицы (1-й параметр), но исключая некоторые столбцы (2-й параметр).

stringlist и putil.join из PL / SQL Commons .

stringlist - это простой список строк: create type StringList as table of varchar2(32767); и putil.join - это просто обычная функция соединения.

create or replace function quote_list(p_list in stringlist)
return stringlist as
  v_list stringlist := stringlist();
begin
  v_list.extend(p_list.last);
  for i in p_list.first .. p_list.last loop
    v_list(i) := '''' || p_list(i) || '''';
  end loop;

  return v_list;
end;
/
show errors

create or replace function query_generator(
  p_table in varchar2,
  p_exclude in stringlist
) return varchar2 as
  v_table constant varchar2(31) := upper(p_table);
  v_exclude constant varchar2(32676) :=
    upper(putil.join(quote_list(p_exclude), ','));
  v_stmt_str constant varchar2(32676) :=
    'select column_name from all_tab_columns where table_name = ''' ||
    v_table || ''' and column_name not in (' || v_exclude ||
    ') order by column_id';
  type stmt_cur_t is ref cursor;
  v_stmt_cur stmt_cur_t;
  v_column_name varchar2(31);
  v_query varchar2(32676) := 'select ';
begin
  open v_stmt_cur for v_stmt_str;

  loop
    fetch v_stmt_cur into v_column_name;
    exit when v_stmt_cur%notfound;
    v_query := v_query || lower(v_column_name) || ', ';
  end loop;

  close v_stmt_cur;

  select rtrim(v_query, ', ') into v_query from dual;

  v_query := v_query || ' from ' || p_table || ';';

  return v_query;
end;
/
show errors

Пример использования:

exec dbms_output.put_line(query_generator('all_tables', stringlist('segment_created', 'result_cache')))
1 голос
/ 20 октября 2015
WITH O AS
(
SELECT 'SELECT ' || rtrim('NULL AS "Dummy",' || LISTAGG('"'||column_name || '"', ',' ) within group (ORDER BY COLUMN_NAME),',')|| ' FROM "'||TABLE_NAME||'"' AS SQL, TABLE_NAME  FROM USER_TAB_COLUMNS  GROUP BY (TABLE_NAME)
)
SELECT DBMS_XMLGEN.GETXMLTYPE ((SELECT REPLACE(SQL,',COLUMNNAME','') FROM O WHERE TABLE_NAME = 'TABLENAME')) FROM DUAL
0 голосов
/ 09 января 2019

Полиморфные табличные функции Oracle 18c позволяют выбирать из таблицы все и исключать список столбцов:

select * from everything_but(employee, columns(hobbies));

ID   FIRSTNAME   LASTNAME
--   ---------   --------
1    John        Smith

Для создания этой функции требуется пакет ниже, скопированный с веб-сайта Тима Холла https://oracle -base.com / статьи / 18c / полиморфный стол-функции-18c .Обратите внимание, что пакет не содержит ничего конкретного для таблицы - это решение будет работать для любой таблицы Oracle.

CREATE OR REPLACE PACKAGE poly_pkg AS

  FUNCTION everything_but(tab IN TABLE,
                          col IN COLUMNS)
  RETURN TABLE PIPELINED
  ROW POLYMORPHIC USING poly_pkg;

  FUNCTION describe (tab IN OUT DBMS_TF.table_t,
                     col IN     dbms_tf.columns_t)
    RETURN DBMS_TF.describe_t;

END poly_pkg;
/


CREATE OR REPLACE PACKAGE BODY poly_pkg AS

  FUNCTION describe (tab IN OUT DBMS_TF.table_t,
                     col IN     dbms_tf.columns_t)
    RETURN DBMS_TF.describe_t
  AS
  BEGIN
    -- Loop through all the table columns.
    FOR i IN 1 .. tab.column.count() LOOP
      -- Loop through all the columns listed in the second parameter.
      FOR j IN 1 .. col.count() LOOP
        -- Set pass_through to true for any columns not in the exclude list.
        tab.column(i).pass_through := (tab.column(i).description.name != col(j));
        -- Exit inner loop if you find a column that shouldn't be included.
        EXIT WHEN NOT tab.column(i).pass_through;
      END LOOP;
    END LOOP;

    RETURN NULL;
  END;

END poly_pkg;
/

Я также создал эту простую функцию-обертку, чтобы дать ей лучшее имя.И создал простой пример таблицы.

CREATE OR REPLACE FUNCTION everything_but(tab IN TABLE, col in COLUMNS)
  RETURN TABLE PIPELINED
  ROW POLYMORPHIC USING poly_pkg;
/

create table employee as
select 1 id, 'John' firstname, 'Smith' lastname, 'fishing' hobbies from dual;
0 голосов
/ 28 июля 2015

вот решения ... мне нужны все столбцы, кроме пароля

(выберите имя_ столбца || ',' из столбцов user_tab_columns, где имя_таблицы = 'USERS' и имя_ столбца <> 'ПАРОЛЬ')

0 голосов
/ 03 февраля 2015

Вот еще один вариант, чтобы получить список полей, который позволяет указать разделитель:

select listagg(column_name, ', ') WITHIN GROUP (ORDER BY rownum)
from all_tab_columns
where table_name='table'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...