【问题标题】:Tricky SQL SELECT statement - combine two rows into two columns棘手的 SQL SELECT 语句 - 将两行合并为两列
【发布时间】:2011-03-13 20:35:35
【问题描述】:

我的问题:
我有一个带有Channel <int>Value <float> 列的表,还有一个时间戳和其他几个带有附加数据的列。 Channel12,并且有 1 或 2 行除了通道和值之外的所有内容都相同。

我想做的是将此数据选择到一个新表单中,其中两个通道显示为列。我试图用GROUP BY 做一些事情,但我不知道如何根据同一行上的通道将值放入正确的列中。

示例:
对于那些宁愿查看我拥有的数据和我想要的数据并从那里弄清楚的人来说,就是这样。我有什么:

 Channel    Value       Timestamp                OtherStuff
 1          0.2394      2010-07-09 13:00:00      'some other stuff'
 2          1.2348      2010-07-09 13:00:00      'some other stuff'
 1          24.2348     2010-07-09 12:58:00      'some other stuff'
 2          16.3728     2010-07-09 12:58:00      'some other stuff'
 1          12.284      2010-07-09 13:00:00      'unrelated things'
 2          9.6147      2010-07-09 13:00:00      'unrelated things'

我想要什么:

Value1     Value2      Timestamp                OtherStuff
0.2394     1.2348      2010-07-09 13:00:00      'some other stuff'
24.2348    16.3728     2010-07-09 12:58:00      'some other stuff'
12.284     9.6147      2010-07-09 13:00:00      'unrelated things'

更新以回应 cmets 中出现的一些问题,以及一些后续问题/澄清:

  • 是的,是TimestampOtherStuff 的组合将这两行链接在一起。 (OtherStuff 实际上不止一列,但为了简洁起见,我进行了简化。)还有一些其他列不一定相等,但应该保持原样。

  • 有问题的表已经从两个表连接,其中ValueChannelTimestamp 来自其中一个,其余的(总共 7 列,其中 4对于“链接”行总是相等的,而其他三个大多不是)。有几个使用 INNER JOIN 的建议 - 如果我已经将东西连接在一起,这些是否仍然有效(即使我没有 myTable 来连接自己)?

  • 很多行具有相同的时间戳,所以我需要来自我要加入的两个表的信息来确定哪些行要链接在一起。

  • 我有很多数据。输入来自遍布全国的测量设备,其中大多数(如果不是全部)每 2 分钟上传一次测量结果(最多 4 个通道)。现在我们有大约 1000 台设备在线,这意味着平均每分钟增加大约 1000 行。我需要考虑至少 3 小时(最好是 6 小时)的值,这意味着表中包含通道、值和时间戳的 180 000 到 360 000 行。

【问题讨论】:

  • 什么链接了 2 行?时间戳和其他东西?
  • 刚刚问了一个与此相反的问题:)!

标签: sql sql-server-2005 tsql group-by


【解决方案1】:

只要你有链接两行的东西,像这样

SELECT
    c1.Value AS Value1, c2.Value AS Value2, c1.timestamp, c2.otherstuff
FROM
    MyTable c1
    JOIN
    MyTable c2 ON c1.timestamp = c2.timestamp AND c1.otherstuff = c2.otherstuff
WHERE
    c1.Channel = 1 AND c2.Channel = 2

如果您没有任何东西可以链接 2 行,那么它可能无法完成,因为您怎么知道它们是配对的?

如果你有 1 个 2 行(编辑:并且不知道你有哪个通道值)

SELECT
    c1.Value AS Value1, c2.Value AS Value2, c1.timestamp, c2.otherstuff
FROM
    (
     SELECT Value, timestamp, otherstuff
     FROM MyTable
     WHERE Channel = 1
    ) c1           
    FULL OUTER JOIN
    (
     SELECT Value, timestamp, otherstuff
     FROM MyTable
     WHERE Channel = 2
    ) c2 ON c1.timestamp = c2.timestamp AND c1.otherstuff = c2.otherstuff                  

【讨论】:

  • 我确实有 1 2 行。如果我只有一行,即使我不一定知道我有哪个频道,第二种方法会不会?
  • 恐怕我过度简化了我的表结构 - 请参阅我的问题的更新。我应该通过首先加入一个表变量来解决我有两个连接表的事实,还是有一个很好的方法来做到这一点,即使不是所有的列都来自同一个表?我想我可以加入另一张桌子,但我应该在哪里这样做以获得最佳性能? (查询已经花了差不多一分钟...)
  • 我注意到这种方法的一个错误,如果 c1 的 channel = 1 在 c2 中找不到,它不会显示,因为 c1 othertuff 在 c2 中不等于 null。
  • 简单的解决方案,不依赖于 MySQL / Oracle 特定的内置函数。 +1
【解决方案2】:

类似...

SELECT   MAX(CASE Channel WHEN 1 THEN Value ELSE 0 END) AS Value1,
         MAX(CASE Channel WHEN 2 THEN Value ELSE 0 END) AS Value2,
         Timestamp, 
         OtherStuff
FROM     {tablename}
GROUP BY Timestamp, OtherStuff

(我还没有测试过这个!) (这假设你的价值总是积极的!)

或者(参见下面的 cmets)...

SELECT   SUM(CASE Channel WHEN 1 THEN Value ELSE 0 END) AS Value1, 
         SUM(CASE Channel WHEN 2 THEN Value ELSE 0 END) AS Value2, 
         Timestamp, 
         OtherStuff 
FROM     {tablename}
GROUP BY Timestamp, OtherStuff

【讨论】:

  • 不幸的是,我不能假设该值始终为正。不过还是谢谢=)
  • 好的,如果通道 1 总是正好 1 行,通道 2 总是正好 1 行(对于每个时间戳),那么请参阅我的替代方案(上图)
  • 不幸的是,事实并非如此 - 我需要 both 时间戳和其他东西(几列)来区分。正如您在我的示例中看到的,可能有两行不属于同一“链接”行的通道 1 和时间戳 13:00。
  • 我认为您需要解释这些行是如何链接的。我的替代解决方案将为您的示例提供正确的结果。它将按 Timestamp 和 OtherStuff 对所有行进行分组 - 然后汇总 Channel=1 的所有值并调用此 Value1,对于 Channel=2 也是如此。
【解决方案3】:
SELECT a.Value as Value1, b.Value as Value2,
a.TimeStamp, a.OtherStuff
FROM myTable a INNER JOIN myTable b
ON a.OtherStuff = b.OtherStuff and a.TimeStamp = b.TimeStamp
WHERE a.Channel = 1 AND b.Channel = 2

在没有查询编辑器的情况下编写。请善待:)

编辑:INNER JOIN 也可以在这里使用。 EDIT2:用 INNER JOIN 更正。不要急于投反对票:)

【讨论】:

  • -1 表示不使用 JOIN。其他开发人员很难看到语法 FROM table1, table2 发生了什么。
  • 无论如何它都是错误的,也是错误的形式。 “a.TimeStamp = 1 AND b.TimeStamp = 2”?
  • @gbn:是的。我已经纠正了。多亏了 SO,有一个编辑功能(想象一下不赞成票)。
  • @JonH:我同意。我曾经在没有JOIN 语法(ms-access)的情况下编写查询。我花了一些时间才想到JOIN
  • 好的,现在你正在使用JOIN,为什么要在JOIN中过滤频道?你应该分开 JOIN 和 WHERE...
猜你喜欢
  • 2010-11-16
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 2011-10-11
  • 2014-10-30
  • 1970-01-01
  • 1970-01-01
  • 2013-05-31
相关资源
最近更新 更多