将两个表连接在一起并在一行中压缩多行

时间:2012-05-17 14:22:19

标签: sql sql-server join

我有两张表如下:

TableOne
- RawDataId int(pk)
- TimeStamp DateTime
- BuildingID int

TableTwo
- RawDataId int(pk / fk)
- MeterId int(pk)
- 价值真实

MeterId不是唯一的并且重复多次(但总是以相同的数量重复)。这两个表连在一起没问题。我能够选择前15行并按时间戳排序,为我提供每个仪表的最新值(总共15个,每个都带有时间戳)。但是,我还需要从之前的时间(恰好是1440和1439分钟前)获得每个仪表的值 - 如果这有意义的话。

因此,在运行查询之后,我需要一个包含TableOne和TableTwo列的表,但是有两个额外的列用于ValueB和ValueC(B早于1440分钟,前面是C 1439)。我整天和昨晚的大部分时间一直玩弄他,我正在慢慢失去这个阴谋。

任何帮助将不胜感激。 谢谢偷看。

---更新

我在下面列出了实际的表格架构以及一些示例数据。

CREATE TABLE [dbo].[TableOne](
[RawDataId] [bigint] IDENTITY(1,1) NOT NULL,
[TimeStamp] [datetime] NOT NULL,
[BuildingId] [int] NULL,
CONSTRAINT [TableOne_PK] PRIMARY KEY CLUSTERED 

CREATE TABLE [dbo].[TableTwo](
[MeterId] [bigint] NOT NULL,
[RawDataId] [bigint] NOT NULL,
[Value] [real] NULL,
 CONSTRAINT [TableTwo_PK] PRIMARY KEY CLUSTERED 

TableOne中最后30条记录的示例数据:

RawDataId, TimeStamp, BuildingId
21677   2012-05-16 00:03:00.000 1
21678   2012-05-16 00:03:00.000 1
21679   2012-05-16 00:03:00.000 1
21680   2012-05-16 00:03:00.000 1
21681   2012-05-16 00:03:00.000 1
21682   2012-05-16 00:03:00.000 1
21683   2012-05-16 00:03:00.000 1
21684   2012-05-16 00:03:00.000 1
21685   2012-05-16 00:03:00.000 1
21686   2012-05-16 00:03:00.000 1
21687   2012-05-16 00:03:00.000 1
21688   2012-05-16 00:03:00.000 1
21689   2012-05-16 00:03:00.000 1
21690   2012-05-16 00:03:00.000 1
21691   2012-05-16 00:03:00.000 1
21662   2012-05-16 00:02:00.000 1
21663   2012-05-16 00:02:00.000 1
21664   2012-05-16 00:02:00.000 1
21665   2012-05-16 00:02:00.000 1
21666   2012-05-16 00:02:00.000 1
21667   2012-05-16 00:02:00.000 1
21668   2012-05-16 00:02:00.000 1
21669   2012-05-16 00:02:00.000 1
21670   2012-05-16 00:02:00.000 1
21671   2012-05-16 00:02:00.000 1
21672   2012-05-16 00:02:00.000 1
21673   2012-05-16 00:02:00.000 1
21674   2012-05-16 00:02:00.000 1
21675   2012-05-16 00:02:00.000 1
21676   2012-05-16 00:02:00.000 1

TableTwo示例:

MeterId, RawDataId, Value
15  21691   7722613
14  21690   908944
13  21689   4982947
12  21688   3821899
11  21687   6
10  21686   0
9   21685   0
8   21684   5761656
7   21683   4240048
6   21682   1541372
5   21681   283223
4   21680   1.298603E+07
3   21679   388137
2   21678   876121
1   21677   0
15  21676   7722615
14  21675   908944
13  21674   4982947
12  21673   3821899
11  21672   5
10  21671   0
9   21670   0
8   21669   5761656
7   21668   4240052
6   21667   1541372
5   21666   283223
4   21665   1.298604E+07
3   21664   388137
2   21663   876122
1   21662   0

每1个表(即时间戳)将表读数写入表中。当选择前15个记录(按TimeStamp排序,为了给我最新的值)时,我还需要获得该仪表1440和1439分钟前的值(相对于最新的TimeStamp)。我希望这更清楚。

到目前为止,我的SQL查询如下所示:

SELECT TOP 15 * FROM (Select TableOne.[RawDataId], 
[TimeStamp], BuildingId, MeterId, `enter code here`Value 
FROM [TableOne]
INNER JOIN TableTwo ON
TableOne = TableTwo) as PS
ORDER BY [TimeStamp];

查询给了我以下内容,但是我需要额外的两列,其中包含1440和1439分钟之前相对于TimeStamp的值:

RawDataId, TimeStamp, BuildingId, MeterId, Value
21677   2012-05-16 00:03:00.000 1   1   0
21678   2012-05-16 00:03:00.000 1   2   876121
21679   2012-05-16 00:03:00.000 1   3   388137
21680   2012-05-16 00:03:00.000 1   4   1.298603E+07
21681   2012-05-16 00:03:00.000 1   5   283223
21682   2012-05-16 00:03:00.000 1   6   1541372
21683   2012-05-16 00:03:00.000 1   7   4240048
21684   2012-05-16 00:03:00.000 1   8   5761656
21685   2012-05-16 00:03:00.000 1   9   0
21686   2012-05-16 00:03:00.000 1   10  0
21687   2012-05-16 00:03:00.000 1   11  6
21688   2012-05-16 00:03:00.000 1   12  3821899
21689   2012-05-16 00:03:00.000 1   13  4982947
21690   2012-05-16 00:03:00.000 1   14  908944
21691   2012-05-16 00:03:00.000 1   15  7722613

3 个答案:

答案 0 :(得分:1)

没有看到数据(也许是查询)样本,很难理解这个问题。如果我理解正确,这应该有效:

SELECT
(
SELECT TOP 1 Value
FROM TableOne t1 join TableTwo t2 ON t1.RawDataId = t2.RawDataId
WHERE t1.RawDataId IN (
SELECT RawDataId FROM TableTwo WHERE MeterId = tbl.MeterId
) and TimeStamp = DATEADD(mi, -1440, tbl.TimeStamp)
) as ValueB,
(
SELECT TOP 1 Value
FROM TableOne t1 join TableTwo t2 ON t1.RawDataId = t2.RawDataId
WHERE t1.RawDataId IN (
SELECT RawDataId FROM TableTwo WHERE MeterId = tbl.MeterId
) and TimeStamp = DATEADD(mi, -1439, tbl.TimeStamp)
) as ValueC
FROM TableTwo tbl

答案 1 :(得分:1)

如果你总是会在1440分钟和1439分钟之前获得价值,那么这样的事情可能有用:

SELECT TOP 15 
      TableOne.BuildingID
    , TableOne.RawDataID
    , TableOne.TimeStamp
    , TableTwo.MeterID
    , TableTwo.Value
    , TableTwo1439.Value AS ValueB
    , TableTwo1440.Value AS ValueC
FROM TableOne
JOIN TableTwo ON TableOne.RawDataID=TableTwo.RawDataID
JOIN TableTwo TableTwo1439 ON TableTwo.MeterID=TableTwo1439.MeterID
JOIN TableOne TableOne1439 ON TableTwo1439.RawDataID=TableOne1439.RawDataID AND TableOne.TimeStamp=DATEADD(MINUTE,-1439,TableOne1439.TimeStamp)
JOIN TableTwo TableTwo1440 ON TableTwo.MeterID=TableTwo1440.MeterID
JOIN TableOne TableOne1440 ON TableTwo1440.RawDataID=TableOne1440.RawDataID AND TableOne.TimeStamp=DATEADD(MINUTE,-1440,TableOne1440.TimeStamp)
ORDER BY TableOne.Timestamp DESC

否则,您仍然可以使用相同的方法,但可能需要调整它以使用OUTER JOIN而不是......

答案 2 :(得分:0)

如果您使用的是SQL Server 2005或更高版本,则可以尝试以下方法:

WITH data AS (
  SELECT
    t1.RawDataId,
    t1.TimeStamp,
    t1.BuildingId,
    t2.MeterId,
    t2.Value,
    x.Diff AS TimeStampId
  FROM (SELECT BuildingId, MAX(TimeStamp) AS TimeStamp FROM TableOne GROUP BY BuildingId) t
    CROSS JOIN (SELECT 0 UNION ALL SELECT 1440 UNION ALL SELECT 1439) x (Diff)
    INNER JOIN TableOne t1 ON t.BuildingId = t1.BuildingId
                          AND t1.TimeStamp = DATEADD(MINUTE, -x.Diff, t.TimeStamp)
    INNER JOIN TableTwo t2 ON t2.RawDataId = t1.RawDataId
)
SELECT
  RawDataId,
  TimeStamp,
  BuildingId,
  MeterId,
  Value           = [0],
  Value1440MinAgo = [1440],
  Value1439MinAgo = [1439]
FROM data
PIVOT (
  MAX(Value) FOR TimeStampId IN ([0], [1440], [1439])
) p

也就是说,我假设您想要考虑各种BuildingIds,因为该列存在于您的输出中。如果您只想要特定的一个,可以像这样重写t子选择:

(SELECT TOP 1 * FROM TableOne WHERE BuildingId = @Id ORDER BY TimeStamp DESC) t