2011-11-14 3 views
0

J'ai la table de DeviceMaster et DeviceStatus. où DeviceMaster est le maître pour les périphériques et DeviceStatus est l'état de l'appareil.Maintenant je veux obtenir l'enregistrement du dernier DeviceStatus de chaque périphérique avec une seule ligne en utilisant le DeviceMasterId et selon le premier en premier (ordre décroissant).créer la requête SQL

par ex.

DeviceName  RecordCreatedDate  Status 
ElectronicRod  14/11/2011 12:00:00  On 
ElectronicRod  14/11/2011 11:30:00  Off 

même s'il existe plusieurs enregistrements dans DeviceStatus.

ici est la structure de la table

DeviceMaster

[Id] [int], 
[ROId] [int] , 
[ClientId] [int] , 
[DeviceTypeId] [int] , 
[Label] [varchar](50) , 
[ClientCommChannelId] [int] , 
[ServerCommChannelId] [bigint] , 
[DeviceName] [varchar](50) , 
[Address] [varchar](50) , 
[Attribute1] [varchar](50) , 
[Attribute2] [varchar](50) , 
[Attribute3] [varchar](50) , 
[IsDeleted] [bit] , 
[RecordCreatedDate] [datetime] , 
[RecordUpdatedDate] [datetime] , 
[RecordCreatedBy] [int] , 
[RecordUpdatedBy] [int] , 
[IsTransfered] [bit] 

devicestatus

[Id] [bigint], 
[ROId] [int], 
[ClientId] [int], 
[ServerDeviceId] [bigint] , --It is the foreign key reference of Device Id 
[ClientDeviceId] [int] , 
[Status] [bit] , 
[TimeStamp] [datetime] , 
[Attribute1] [varchar](50) , 
[Attribute2] [varchar](50) , 
[Attribute3] [varchar](50) , 
[RecordCreatedDate] [datetime] , 
[RecordUpdatedDate] [datetime] , 
[RecordCreatedBy] [int] , 
[RecordUpdatedBy] [int] , 
[IsTransfered] [bit] 

devicestatus ont l'entrée multiple ligne unique device.I besoin de la dernière devicestatus pour chaque et chaque appareil.

Nous vous remercions à l'avance

+1

Pouvez-vous afficher la structure de la table? Aussi qu'avez-vous essayé vous-même? avez-vous du code etc? – Purplegoldfish

+0

@Purplegoldfish sure –

+0

Pouvez-vous préciser si le DeviceStatus est un tableau d'audit montrant l'historique des changements d'état et non l'état actuel. –

Répondre

1

Vous pouvez utiliser un CTE (Common Table Expression) avec la fonction ROW_NUMBER:

;WITH LastPerDevice AS 
(
    SELECT 
     dm.DeviceName, ds.RecordCreatedDate, ds.Status, 
     ROW_NUMBER() OVER(PARTITION BY dm.DeviceMasterId 
         ORDER BY ds.RecordCreatedDate DESC) AS 'RowNum' 
    FROM dbo.DeviceMaster dm 
    INNER JOIN dbo.DeviceStatus ds ON ds.DeviceMasterId = dm.DeviceMasterId 
) 
SELECT 
    DeviceName, RecordCreatedDate, Status 
FROM LastPerDevice 
WHERE RowNum = 1 

Ce CTE "partitions" de vos données par DeviceMasterId, et pour chaque partition, ROW_NUMBER la fonction distribue des numéros séquentiels, commençant à 1 et ordonnée par RecordCreatedDate DESC - donc la ligne la plus récente obtient RowNum = 1 (pour chaque DeviceMasterId) qui est ce que je sélectionne du CTE dans l'instruction SELECT après elle.

+0

Merci beaucoup :) ça marche parfaitement –

+0

Nice. Si vos tableaux sont très volumineux, je vous suggérerais d'effectuer un test de performance à ce sujet. (Exécuter avec SET STATISTICS IO ON). Comparez avec l'une des autres réponses ici et soit voir qui donne le plus faible IO/effort. –

0
select dm.DeviceName, ds1.LatestDate, ds2.Status 
from DeviceMaster dm, 
    (select ServerDeviceId, max(RecordCreatedDate) as LatestDate 
    from DeviceStatus 
    group by ServerDeviceId) ds1, 
    DeviceStatus ds2 
where dm.Id = ds1.ServerDeviceId 
    and dm.Id = ds2.ServerDeviceId 
    and ds1.LatestDate = ds2.RecordCreatedDate 
order by ds1.LatestDate desc 
+0

OK, j'ai fini de marteler ça ... S'il vous plaît essayez-le :) – kol

0

Je ne suis pas certain de ce que vous cherchez, mais ce qui suit utilise une sous-requête dans la clause where pour filtrer la dernière date. Peut-être que si ce n'est pas exactement ce que vous cherchez, cela peut vous aider à le trouver. Faites-moi savoir si vous avez besoin de moi pour clarifier quoi que ce soit.

select DeviceName, RecordCreateDated, Status 
    from DeviceMaster dm join 
      DeviceStatus ds on dm.Id = ds.ServiceDeviceId 
    where DeviceName = 'ElectronicRod' and 
      RecordCreateDate = 
       (select max(RecordCreatedDate) 
       from DeviceMaster dm1 join 
         DeviceStatus ds1 on dm1.Id = ds1.ServiceDeviceId 
       where dm1.DeviceName = dm.DeviceName) 
0

utilisation maximum(), groupe par la méthode

votre code ressemblera probbly un peu comme ceci:

SELECT max("DeviceStatus") as "devicestatus" , "Id" FROM "DeviceMaster" 
group by "Id"; 

EDIT:

SELECT max("RecordCreatedDate") as "Date" , "DeviceName" FROM "DeviceMaster" 
group by "Name"; 
+0

S'il s'agit d'un BIT, le maximum sera toujours 1 (sauf si le statut est toujours 0). Vous ne voulez pas le MAX, vous voulez le dernier! –

0

Vous voulez obtenir l'état du dernier enregistrement dans la table d'état pour chaque périphérique. Cela signifie que vous devez réellement faire deux jointures à la table d'état - une table pour obtenir la dernière ligne (regroupement par le périphérique), puis à nouveau pour obtenir le statut de ce dernier statut. Comme ceci:

Je vois que vous avez des BIGINTS - cela me suggère que la table d'état est grande. Cela suggère qu'il est mis à jour très fréquemment. Assurez-vous que la table d'état est indexée sur ServerDeviceId.

select DeviceName ,ds.RecordCreatedDate,ds.Status 
from 
DeviceMaster dm inner join 
(select ServerDeviceId,MAX(Id) DeviceStatusId from DeviceStatus 
group by ServerDeviceId) laststatus 
    on laststatus.ServerDeviceId= dm.Id inner join 
DeviceStatus ds 
    on ds.Id = laststatus.DeviceStatusId 
+0

C'est presque le même que le mien :) Vous avez fait un meilleur travail en utilisant max (Id) et en rejoignant les tables d'état sur Id - je les ai rejoints sur ServerDeviceId et la date de création, ce qui est un peu stupide. Ajoutez l'ordre décroissant selon ds.RecordCreatedDate, et cette solution devient parfaite :) – kol