我有以下名为_kv的Oracle 10g表:
select * from _kv
ID K V
---- ----- -----
1 name Bob
1 age 30
1 gender male
2 name Susan
2 status married
我想使用纯SQL(而不是PL / SQL)将我的密钥转换为列,以便生成的表看起来像这样:
ID NAME AGE GENDER STATUS
---- ----- ----- ------ --------
1 Bob 30 male
2 Susan married
K
一样多的列(没有那么多)当您知道可以调用您的透视列时,有很多示例,但我无法为Oracle找到通用的透视解决方案。
谢谢!
答案 0 :(得分:29)
Oracle 11g提供了PIVOT
操作,可以执行您想要的操作。
Oracle 11g解决方案
select * from
(select id, k, v from _kv)
pivot(max(v) for k in ('name', 'age', 'gender', 'status')
(注意:我没有11g的副本来测试这个,所以我还没有验证它的功能)
我从http://orafaq.com/wiki/PIVOT
获得了此解决方案 EDIT - pivot xml选项(也是Oracle 11g)
显然,当您不知道可能需要的所有可能的列标题时,还有一个pivot xml
选项。 (请参阅位于http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html的页面底部附近的 XML TYPE 部分)
select * from
(select id, k, v from _kv)
pivot xml (max(v)
for k in (any) )
(注意:和以前一样,我没有11g的副本来测试它,所以我还没有验证它的功能)
Edit2:将v
和pivot
语句中的pivot xml
更改为max(v)
,因为它应该按照其中一个提及进行汇总评论。我还添加了in
子句,这对pivot
不是可选的。当然,必须在in
子句中指定值会使得完全动态的pivot / crosstab查询的目标失败,就像这个问题的海报一样。
答案 1 :(得分:6)
要处理可能存在多个值的情况(在您的示例中为v),我使用public class MainActivity extends ActionBarActivity {
private EditText MyNumber;
private ImageView MyImage;
private ListView MyIndexList;
private ArrayList<HashMap<String,String>> list = new ArrayList<>();
private ArrayList<HashMap<Integer,Bitmap>> list2 = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyNumber = (EditText)findViewById(R.id.choiceofindex);
MyImage = (ImageView)findViewById(R.id.imageRecup);
MyIndexList = (ListView)findViewById(R.id.listIndex);
}
class GetImageTask extends AsyncTask<Integer,Integer,Bitmap> {
protected Bitmap doInBackground(Integer... index) {
HashMap<String,String> hashmap = new HashMap<>();
HashMap<Integer,Bitmap> hashmap2 = new HashMap<>();
Integer choix = index[0];
String urldisplay = "http://example.com/image.php?index=" + choix;
Bitmap RecupImage = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
RecupImage = BitmapFactory.decodeStream(in);
}
catch (Exception e){
Log.e("Error", e.getMessage());
e.printStackTrace();
}
hashmap.put("index","index " +choix);
hashmap2.put(choix,RecupImage);
list.add(hashmap);
list2.add(hashmap2);
return RecupImage;
}
protected void onProgressUpdate(Integer... progress)
{
Context context = getApplicationContext();
super.onProgressUpdate(progress);
Toast.makeText(context, "Wait...", Toast.LENGTH_LONG).show();
}
protected void onPostExecute(Bitmap result)
{
Context context = getApplicationContext();
super.onPostExecute(result);
MyImage.setImageBitmap(result);
Toast.makeText(context, "Image!!", Toast.LENGTH_LONG).show();
}
}
public void onClickRecup(View v)
{
try{
int index= Integer.parseInt(MyNumber.getText().toString());
GetImageTask GetImage = new GetImageTask();
GetImage.execute(index);
}
catch (NumberFormatException nfe) {
Context context = getApplicationContext();
Toast.makeText(context, "No image!", Toast.LENGTH_LONG).show();
}
}
public void onClickIndex(View v)
{
try {
SimpleAdapter adapter = new SimpleAdapter(this,list,R.layout.row, new String[]{"index"},
new int[] {R.id.index});
MyIndexList.setAdapter(adapter);
MyIndexList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Bitmap Imageback = list2.get(position).get(R.id.index);
MyImage.setImageBitmap(Imageback);
}
});
}
catch (Exception e){
Context context = getApplicationContext();
Toast.makeText(context, "Problem on ListView", Toast.LENGTH_LONG).show();
}
}
}
和PIVOT
:
LISTAGG
由于您需要动态值,因此在调用pivot语句之前,请使用动态SQL并传入在表数据上运行select所确定的值。
答案 2 :(得分:5)
发生在枢轴上的任务。以下对我的测试仅适用于11g:
select * from
(
select ID, COUNTRY_NAME, TOTAL_COUNT from ONE_TABLE
)
pivot(
SUM(TOTAL_COUNT) for COUNTRY_NAME in (
'Canada', 'USA', 'Mexico'
)
);
答案 3 :(得分:2)
首先,需要再次使用pivot xml
进行动态调整。我们有另一种方法可以通过将列名存储在变量中并将它们传递给动态sql,如下所示。
考虑我们有一个如下表格。
如果我们需要将YR
列中的值显示为列名称,并将QTY
中的值显示在那些列中,那么我们可以使用以下代码。
declare
sqlqry clob;
cols clob;
begin
select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
into cols
from (select distinct YR from EMPLOYEE);
sqlqry :=
'
select * from
(
select *
from EMPLOYEE
)
pivot
(
MIN(QTY) for YR in (' || cols || ')
)';
execute immediate sqlqry;
end;
/
结果