如何将结果集中的单行表示为多行?

时间:2010-01-28 12:17:25

标签: sql mysql

例如,给出了包含这些列的货币汇率表(在这里使用3,但在我的情况下,大约有30个):

  date     | eur | usd | gbp
2010-01-28 | X   | Y   | Z

如何将其转换为此版本(使用具有最新日期的行):

currency | rate
eur      | X
usd      | Y
gbp      | Z

我想出了这样的查询:

SELECT 'eur' AS currency, eur AS rate FROM rates WHERE date = (SELECT MAX(date) FROM rates)
UNION
SELECT 'usd' AS currency, usd AS rate FROM rates WHERE date = (SELECT MAX(date) FROM rates)
UNION
...

这是巨大而丑陋的。还有其他解决方案吗?

3 个答案:

答案 0 :(得分:5)

有时最简单的解决方案(如果您需要漂亮的查询)是重新设计架构。可能最好的解决方案是将您的表格更改为:

   date    | currency | rate
-----------+----------+-----
2010-01-28 |   eur    |  X
2010-01-28 |   usd    |  Y
2010-01-28 |   gbp    |  Z

在日期和货币上有适当的索引以表现。这就是应该在3NF中的方式,因为费率相互依赖,违反了3NF规则:

  

每一栏必须取决于钥匙,整个钥匙以及钥匙,所以请帮助我Codd。

(我喜欢那个小曲子)。另一种方法是提供一个视图,它执行相同的操作,然后查询视图。这对于DBMS而言同样重要,但你的查询至少看起来更漂亮(create view看起来仍然看起来很丑陋。)

或者您可以接受这样的事实,即某些查询看起来很难看,记录得很好,然后继续: - )

答案 1 :(得分:0)

编辑:忘了这篇文章。我刚看到你正在使用MySQL

如果您正在使用MS-SQL,则可以使用UNPIVOT语句:

SELECT
      date,
      unpiv.ColumnName AS Currency, -- will contain 'eur', 'usd' and so on
      unpiv.ColumnValue AS Rate -- will contain the numeric values
 FROM
      /* your original FROM statement */
      Unpivot (ColumnValue FOR ColumnName in (eur, usd /* add more columns here */)) as unpiv

答案 2 :(得分:0)

您是否必须在SQL中执行此操作?

使用编程语言非常简单。

在PHP中:

$q = mysql_query("
  SELECT    eur, usd, gbp
  FROM      rates
  ORDER BY  date DESC 
  LIMIT 1
");

$table = false;
if($val = mysql_fetch_array($q, MYSQL_ASSOC))
{
  $table = array(
    'eur' => $val['eur'],
    'usd' => $val['usd'],
    'gbp' => $val['gbp'],
  );
}
echo "currency | rate\n";
echo "-----------------";
foreach($table as $cur => $rate)
  echo $curr."      | ".$rate."\n";