我得到一张表X
(有一行):
COL_XA COL_VG COL_LF COL_EQ COL_PP COL_QM ...
1 0 0 0 1 1
每列COL_x
只能包含值0或1.
我想将此表格转换为此格式Y
:
NAME
"COL_XA"
"COL_PP"
"COL_QM"
...
此表应仅打印表X
中第一行(也是唯一一行)的值为1的列。
这个问题与任何其他关于换位的问题有关,区别在于我不想要实际值,而是列名,这些名称是事先不知道的。
我可以使用Excel或PL / SQL创建表单的字符串列表
MIN(CASE WHEN t.COL_XA = 1 THEN 'COL_XA' ELSE null END) as NAME
,但此解决方案效率低下(EXECUTE IMMEDIATE
)并且难以维护。传递给EXECUTE IMMEDIATE
的字符串限制为32700个字符,在生产中很容易超出,而表X
可以有超过500个字段。
答案 0 :(得分:1)
这是解决方案,但我必须将其分为两部分
首先提取表的所有列名。我用LISTAGG来收集分隔的列名, 我将在第二个查询中使用第一个查询的输出。
select listagg(column_name,',') WITHIN GROUP (ORDER BY column_name )
from user_tab_cols where upper(table_name)='X'
上述查询的输出将类似于COL_XA,COL_VG,COL_LF,COL_EQ,COL_PP,COL_QM ......等等。
复制上面的输出并用于下面的查询替换
select NAME from X
unpivot ( bit for NAME in (<outputvaluesfromfirstquery>))
where bit=1
我正在尝试合并上面的两个,但我有选择pivot xml但不适用于unpivot xml。
答案 1 :(得分:1)
要完全自动化查询,您必须能够读取实际游标的列名。在PL / SQL中,这可以使用DBMS_SQL(其他方式将在JDBC中)。基于this OTN thread这里的基本表函数。
重要部分是
1) dbms_sql.parse 以文本字符串形式提供的查询和 dbms_sql.execute 它
2) dbms_sql.describe_columns 以获取从表x上的查询返回的列名列表
3) dbms_sql.fetch_rows 获取第一行
4)循环列并检查 dbms_sql.column_value ,如果等于1输出column_name(使用PIPE)
create or replace type str_tblType as table of varchar2(30);
/
create or replace function get_col_name_on_one return str_tblType
PIPELINED
as
l_theCursor integer default dbms_sql.open_cursor;
l_columnValue varchar2(2000);
l_columnOutput varchar2(4000);
l_status integer;
l_colCnt number default 0;
l_colDesc dbms_sql.DESC_TAB;
begin
dbms_sql.parse( l_theCursor, 'SELECT * FROM X', dbms_sql.native );
for i in 1 .. 1000 loop
begin
dbms_sql.define_column( l_theCursor, i,
l_columnValue, 2000 );
l_colCnt := i;
exception
when others then
if ( sqlcode = -1007 ) then exit;
else
raise;
end if;
end;
end loop;
dbms_sql.define_column( l_theCursor, 1, l_columnValue, 2000 );
l_status := dbms_sql.execute(l_theCursor);
dbms_sql.describe_columns(l_theCursor,l_colCnt, l_colDesc);
if dbms_sql.fetch_rows(l_theCursor) > 0 then
for lColCnt in 1..l_colCnt
loop
dbms_sql.column_value( l_theCursor, lColCnt, l_columnValue );
--DBMS_OUTPUT.PUT_LINE( l_columnValue);
IF (l_columnValue = '1') THEN
DBMS_OUTPUT.PUT_LINE(Upper(l_colDesc(lColCnt).col_name));
pipe row(Upper(l_colDesc(lColCnt).col_name));
END IF;
end loop;
end if;
return;
end;
/
select * from table(get_col_name_on_one);
COLUMN_LOOOOOOOOOOOOOONG_100
COLUMN_LOOOOOOOOOOOOOONG_200
COLUMN_LOOOOOOOOOOOOOONG_300
COLUMN_LOOOOOOOOOOOOOONG_400
COLUMN_LOOOOOOOOOOOOOONG_500
COLUMN_LOOOOOOOOOOOOOONG_600
COLUMN_LOOOOOOOOOOOOOONG_700
COLUMN_LOOOOOOOOOOOOOONG_800
COLUMN_LOOOOOOOOOOOOOONG_900
COLUMN_LOOOOOOOOOOOOOONG_1000
使用此解决方案时,您不应该遇到使用宽表的麻烦,我使用带有长列名称的1000列表进行了测试。
答案 2 :(得分:0)
你可以使用一堆resources :trips
root 'trips#index'
s来执行此操作:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="160dp"
android:layout_height="200dp"
android:layout_gravity="top|left"
android:layout_weight="1"
android:layout_margin="8dp"
app:cardCornerRadius="0dp"
app:elevation="5dp">
<ImageView
android:id="@+id/avatar"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_gravity="top|center"
android:scaleType="centerCrop"
android:src="@drawable/wp" />
<TextView
android:id="@+id/album_name"
android:layout_width="match_parent"
android:layout_height="25dp"
android:alpha="0.85"
android:background="@color/light"
android:layout_above="@+id/detail"
android:layout_below="@+id/avatar"
android:gravity="bottom|center"
android:layout_alignParentBottom="true"
android:text="Test"
android:textColor="@color/cardview_dark_background" />
<TextView
android:id="@+id/detail"
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_gravity="bottom|center"
android:alpha="0.85"
android:background="@color/light"
android:gravity="bottom|center"
android:layout_alignParentBottom="true"
android:layout_below="@+id/album_name"
android:text="Test"
android:textColor="@color/dim_foreground_disabled_material_dark" />
</android.support.v7.widget.CardView>
</LinearLayout>
编辑:
如果您只有一行,那么您不需要:
union all
您可以简单地使用:
select 'COL_XA' as name from table t where col_xa = 1 union all
select 'COL_VG' as name from table t where col_vg = 1 union all
. . .
一行不需要 MIN(CASE WHEN t.COL_XA = 1 THEN 'COL_XA' ELSE null END) as NAME
,(CASE WHEN t.COL_XA = 1 THEN 'COL_XA' END)
是多余的。