1

我的数据在“正常”查询中会如下所示:

Val1    Val2
----    ----
1   2
2   [blank]
3   2
4
5   1
6   3
..
96  1

不过,我想要的是这样的(我需要将行数限制为 12):

Val1    Val2    Val1    Val2    Val1    Val2    ... Val1    Val2
----    ----    ----    ----    ----    ----
1   2   13  1   25  [blank]  ...    85  1
2   [blank] 14  1   26  3   ... 86  [blank]
..  ... ... ... ... ... ... ... ...
12  1   24  [blank] 36  2   ... 96  3

是否有一个选择语句可以给我?我不是 SQL 专家,但我在想一些事情(语义上)沿着这些思路:

select (select val1, val2 from dbtable where val1 < 13),
(select val1, val2 from dbtable where val1 > 12 and val1 < 25),
...
(select val1, val2 from dbtable where val1 > 84)
from dbtable

更新

响应 dfb 的 sql 示例:

当我这样做时:

SELECT t1.Val1, t1.Val2 FROM 
(SELECT Val1, Val2, rownum() as rownum FROM dbTable) t1 
INNER JOIN (SELECT Val1, Val2, rownum() as rownum FROM dbTable) t2 
ON t1.rownum/2 == t2.rownum/2

...我得到“未在预期的地方找到 FROM 关键字”

当我这样做时(删除“rownum()”的东西):

SELECT t1.Val1, t1.Val2 FROM 
(SELECT Val1, Val2 FROM dbTable) t1 
INNER JOIN (SELECT Val1, Val2 FROM dbTable) t2 
ON t1.rownum/2 == t2.rownum/2

...我收到“ORA-01747:无效的 user.table.column、table.column 或列规范”

更新 2

Sully 的例子是最接近的,虽然我希望 UNION SQL 能够工作——如果它可以在不压低有效值的情况下完成会更好。事实上,我有正确的布局,但 val 并没有出现在 16X12 布局中我需要它们的位置。无论如何,为了后代的缘故,下面是动态创建行和列的方式(不像下面的代码所示,并且彼此不完全相同):

//prebuild 12 rows in outputDt 
int iRows = 12;
while (iRows > 0)
{
    DataRow row = outputDt.NewRow();
    outputDt.Rows.Add(row);
    iRows -= 1;
}

//prebuild 16 cols in outputDt 
int iCols = 16;
while (iCols > 0) {
    DataColumn col = new DataColumn();
    outputDt.Columns.Add(col);
    iCols -= 1;
}

最后更新

得到它的工作。请参阅是否可以使用交替的垂直列填充 DataGridView?

4

3 回答 3

2

你可以这样做,但它并不漂亮。关于在表示层中执行此操作的评论是正确的。

SELECT ... FROM
(SELECT v1,v2,rownum as rn FROM Foo WHERE mod(rownum,2)=1) t1
INNER JOIN (SELECT v1,v2,rownum as rn FROM Foo WHERE mod(rownum,2)=0) t2
ON (t1.rn/2 = t2.rn/2)
于 2012-08-22T17:57:20.600 回答
2

如果您知道行数将始终为 96,那么这是静态旋转技术之一

select val1 AS col1, val2 AS col2,NULL AS Col3,NULL AS Col4 ,NULL AS Col5,NULL AS Col6,NULL AS col7,NULL AS Col8 from dbtable where val1 < 13
UNION 
select NULL AS col1,NULL AS col2 ,val1 AS Col3, val2 AS Col4,NULL AS Col5,NULL AS Col6,NULL AS col7,NULL AS Col8 from dbtable where val1 > 12 and val1 < 25
UNION
select NULL AS col1,NULL AS col2 ,NULL AS Col3, NULL AS Col4,val1 AS Col5,val2 AS Col6,NULL AS col7,NULL AS Col8 from dbtable where val1 > 25 and val1 < 37
.....
...AND So ON

如果行数未知,那么您需要进行动态透视。

注意:以上语法适用于 SQL Server 2008,我希望它不会与 Oracle 不同。

于 2012-08-22T18:26:57.513 回答
2

这样做的好处是,如果您最终获得更多数据,它只会根据需要构建更多水平列,但永远不会超过 12 行数据。如果您需要显示更多数据,“in-SQL”方式将需要更改代码。

免责声明:这完全是即兴的(C#,因为那是我习惯的)。可能有更好的方法可以做到这一点(Linq?)逻辑应该非常接近,但这使您可以灵活地将该数据列表用于其他目的,而不是这个非常狭窄的显示。

DataTable dt = ResultsFromSproc();
DataTable outputDt = new DataTable();

//prebuild 12 rows in outputDt
int iRows = 12;
while(iRows > 0) {
    outputDt.Rows.Add(new DataRow());
    iRows-=1;
}

int outputColumn = 0;
for(int i = 0; i < dt.Rows.Count; i+=1){
    DataRow dr = dt.Rows[i];

    if(i % 12 == 0 && i > 0) { 
        //add two more columns to outputDt
        outputDt.Columns.Add() //Not sure but you might need to give it a name. (outputColumn+2).ToString() should work
        outputDt.Columns.Add() //Not sure but you might need to give it a name. (outputColumn+3).ToString() should work
        outputColumn += 1;
    }
    outputDt.Rows[i%12][outputColumn] = dr[0];
    outputDt.Rows[i%12][outputColumn + 1] = dr[1];
}
//Step2: Bind to outputDt. Step 3: Profit!

替代版本:对于 val1 == 48 进入单元格 48 的要求(见评论)

DataTable dt = ResultsFromSproc();
DataTable outputDt = new DataTable();

//prebuild 12 rows in outputDt
int iRows = 12;
while(iRows > 0) {
    outputDt.Rows.Add(new DataRow());
    iRows-=1;
}

int outputColumn = 0;
int iMaxCell = (int)dt.Select("MAX(Val1)")[0][0];
//ASSUMING YOU HAVE ALREADY DONE AN ORDER BY Val1 in SQL (if not you need to sort it here first)
for(int i = 0; i < iMaxCell; i+=1){
    DataRow dr = dt.Rows[i];

    if(i % 12 == 0 && i > 0) { 
        //add two more columns to outputDt
        outputDt.Columns.Add() //Not sure but you might need to give it a name. (outputColumn+2).ToString() should work
        outputDt.Columns.Add() //Not sure but you might need to give it a name. (outputColumn+3).ToString() should work
        outputColumn += 2;
    }
    //compare to i+1 if your data starts at 1
    if((int)dr[0] == (i+1)){
        outputDt.Rows[i%12][outputColumn] = dr[0];
        outputDt.Rows[i%12][outputColumn + 1] = dr[1];
    }
}
//Step2: Bind to outputDt. Step 3: Profit!
于 2012-08-22T18:27:17.403 回答