Na sequência desta pergunta , gostaria de saber se existe uma maneira melhor e/ou mais eficiente de coletar os dados em questão.
Conforme declarado, esta consulta me retorna 95% dos dados de que preciso -
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';
Existe uma maneira de obter o mesmo resultado (para cada dispositivo, selecione o TOP Heartbeat ordenado DESC por DateEntered), mas também selecione a linha inteira da [Heartbeats]
tabela? No momento, só recebo o DateTime
para essa linha.
Se eu incluir as colunas adicionais na GROUP BY
cláusula, posso adicioná-las ao select; mas então recebo várias linhas por [Devices]
linha que não quero. Parece estranho, mas o que eu basicamente quero fazer é fazer uma consulta [Devices]
e, em seguida, fazer uma for...each
sobre esse conjunto e adicionar a [Heartbeats]
linha superior para essa [Devices]
linha. Isso é possível?
atualização Esta é a estrutura da tabela Heartbeats:
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
Você pode fazer isso facilmente com
OUTER APPLY
(se estiver em 2005 ou mais recente). Observe que pode haver maneiras de alcançar o resultado com melhor desempenho, como usarROW_NUMBER()
- verifique os planos de execução em caso de dúvida. Além disso,SELECT *
é preguiçoso e desaconselhável; Estou fazendo isso aqui apenas para fins ilustrativos e porque não conheço a estrutura real da tabela Heartbeats.Consulte os livros on-line para obter os pontos mais sutis de
OUTER APPLY
vs.CROSS APPLY
(é muito parecido comOUTER JOIN
vs.INNER JOIN
). Sempre foi uma dor de cabeça fazer consultas como essa no SQL Server 2000, onde você não tinhaOUTER/CROSS APPLY
ou aROW_NUMBER()
função.Você pode tentar usar este tipo de "autojunção":