この質問 のフォローアップとして、問題のデータを収集するためのより良い、および/またはより効率的な方法があるかどうか疑問に思っています。
前述のように、このクエリは必要なデータの95%を返します-
SELECT dv.Name
,MAX(hb.[DateEntered]) as DE
FROM
[Devices] as dv
INNER JOIN
[Heartbeats] as hb ON hb.DeviceID = dv.ID
GROUP BY dv.Name
HAVING MAX(hb.[DateEntered]) < '20130304';
同じ結果を達成する方法はありますか(デバイスごとに、DateEnteredによってDESCで注文されたTOPハートビートを選択します)、さらに行全体を選択します[Heartbeats]
テーブルから?現在、その行のDateTime
のみを取得しています。
GROUP BY
句に追加の列を含めると、それらをselectに追加できます。しかし、私は不要な[Devices]
行ごとに複数の行を取得します。奇妙に聞こえますが、私が基本的にやりたいのは、[Devices]
に対してクエリを実行し、そのセットに対してfor...each
を実行して、その[Heartbeats]
行を追加することです[Devices]
行。それは可能ですか?
updateこれはハートビートテーブルの構造です。
CREATE TABLE [dbo].[Heartbeats](
[ID] [int] IDENTITY(1,1) NOT NULL,
[DeviceID] [int] NOT NULL,
[IsFMSFMPUp] [bit] NOT NULL,
[IsFMSWebUp] [bit] NOT NULL,
[IsPingUp] [bit] NOT NULL,
[DateEntered] [datetime] NOT NULL,
CONSTRAINT [PK_Heartbeats] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [CommonQueryIndex] ON [dbo].[Heartbeats]
(
[DateEntered] ASC,
[DeviceID] ASC
)
INCLUDE ( [ID],
[IsFMSFMPUp],
[IsFMSWebUp],
[IsPingUp]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [HeartbeatDeviceIndex] ON [dbo].[Heartbeats]
(
[DeviceID] ASC
)
INCLUDE ( [ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object: Default [DF_Heartbeats_DateEntered] Script Date: 03/05/2013 10:45:45 ******/
ALTER TABLE [dbo].[Heartbeats] ADD CONSTRAINT [DF_Heartbeats_DateEntered] DEFAULT (getdate()) FOR [DateEntered]
GO
/****** Object: ForeignKey [FK_Heartbeats_Devices] Script Date: 03/05/2013 10:45:45 ******/
ALTER TABLE [dbo].[Heartbeats] WITH CHECK ADD CONSTRAINT [FK_Heartbeats_Devices] FOREIGN KEY([DeviceID])
REFERENCES [dbo].[Devices] ([ID])
GO
ALTER TABLE [dbo].[Heartbeats] CHECK CONSTRAINT [FK_Heartbeats_Devices]
GO
_OUTER APPLY
_を使用すると、これをかなり簡単に実行できます(2005以降の場合)。 ROW_NUMBER()
を使用するなど、結果を達成するためのより良いパフォーマンスの方法があることに注意してください-疑わしい場合は実行プランを確認してください。また、_SELECT *
_は遅延してお勧めできません。ここでは、説明のためにこれを実行しています。ハートビートテーブルの実際の構造がわからないためです。
_SELECT
dv.Name,
hb.*
FROM [Devices] as dv
OUTER APPLY (
SELECT TOP 1 *
FROM Heartbeats
WHERE Heartbeats.DeviceID = dv.ID
ORDER BY DateEntered DESC
) hb
WHERE ISNULL(hb.DateEntered, '1900-01-01T00:00') < '2013-03-04T00:00'
_
_OUTER APPLY
_と_CROSS APPLY
_の細かい点については、Books Onlineを参照してください(これは_OUTER JOIN
_と_INNER JOIN
_によく似ています)。 SQL Server 2000でこのようにクエリを実行するのは常に大変で、_OUTER/CROSS APPLY
_ orROW_NUMBER()
関数がありませんでした。
このタイプの「自己結合」を使用してみてください。
select dat.*
from
(SELECT dv.Name,MAX(hb.[DateEntered]) as DE
FROM [Devices] as dv
INNER JOIN [Heartbeats] as hb ON hb.DeviceID = dv.ID
GROUP BY dv.Name
HAVING MAX(hb.[DateEntered]) < '20130304') grp
inner join
(SELECT dv.Name, hb.*
FROM [Devices] as dv
INNER JOIN [Heartbeats] as hb ON hb.DeviceID = dv.ID) dat
on grp.name = dat.name and grp.DE = dat.[DateEntered]