select une list distincte d'identifiants de la table avec la première valeur dans la même table

J'ai le tableau suivant,

SDate Id Balance 2016-01-01 ABC 3 2016-01-01 DEF 7 2016-01-01 GHI 2 2016-02-01 ABC 6 2016-02-01 DEF 4 2016-02-01 GHI 8 2016-02-01 XYZ 12 

J'ai besoin d'écrire une requête qui me donne une list distincte de Id sur une plage de dates (donc dans cet exemple SDate >= '2016-01-01' et SDate <= '2016-02-01' ) mais aussi me donner le premier équilibre de sorte que le résultat de la table ci-dessus je voudrais voir est,

  Id Balance ABC 3 DEF 7 GHI 2 XYZ 12 

Est-ce possible?

METTRE À JOUR

Désolé, j'aurais dû préciser que pour chaque date, l'identifiant est unique.

Cela devrait être possible avec une fonction de window – tout ce que vous avez à faire est

  • partition par identifiant
  • atsortingbuer un numéro de ligne, et
  • select la ligne du haut pour chaque identifiant

Exemple:

 select id, balance from ( select id, balance, row_number() over( partition by id order by SDate ) as row_num from table1 where SDate between '2016-01-01' and '2016-02-01' ) as a where row_num = 1 

Remarque: l'avantage de cette méthode est qu'elle est beaucoup plus flexible. Supposons que vous vouliez les 2 loggings les plus anciens, vous pouvez juste changer where row_num <= 2 .

Vous pouvez le faire avec une table dérivée qui SDate valeur SDate minimale pour chaque valeur d' Id . En utilisant ceci, vous revenez à votre table d'origine pour find l' Balance de la ligne qui correspond à ces valeurs:

 declare @t table(SDate date,Id nvarchar(3),Balance int); insert into @t values ('2016-01-01','ABC',3),('2016-01-01','DEF',7),('2016-01-01','GHI',2),('2016-02-01','ABC',6),('2016-02-01','DEF',4),('2016-02-01','GHI',8),('2016-02-01','XYZ',12); declare @StartDate date = '20160101'; declare @EndDate date = '20160201'; with d as ( select Id ,min(SDate) as MinSDate from @t where SDate between @StartDate and @EndDate group by id ) select d.Id ,t.Balance from d inner join @tt on(d.Id = t.Id and d.MinSDate = t.SDate ); 

Sortie:

 Id | Balance ----+-------- ABC | 3 DEF | 7 GHI | 2 XYZ | 12 

Analytic row_number() devrait être le plus rapide

 select * from ( select t.*, row_number() over (partition by Id order by SDate) rn from your_table t ) t where rn = 1; 

Vous pouvez y parvenir avec une auto-jointure, ce qui n'est peut-être pas la solution la plus rapide ou la plus élégante:

  CREATE TABLE #SOPostSample ( SDate DATE , Id NVARCHAR(5) , Balance INT ); INSERT INTO #SOPostSample ( SDate, Id, Balance ) VALUES ( '2016-01-01', 'ABC', 3 ), ( '2016-01-01', 'DEF', 7 ), ( '2016-01-01', 'GHI', 2 ), ( '2016-02-01', 'ABC', 6 ), ( '2016-02-01', 'DEF', 4 ), ( '2016-02-01', 'GHI', 8 ), ( '2016-02-01', 'XYZ', 12 ); SELECT t1.Id , MIN(t2.Balance) Balance FROM #SOPostSample t1 INNER JOIN #SOPostSample t2 ON t1.Id = t2.Id GROUP BY t1.Id , t2.SDate HAVING t2.SDate = MIN(t1.SDate); DROP TABLE #SOPostSample; 

Produit:

 id Balance ============ ABC 3 DEF 7 GHI 2 XYZ 12 

Cela fonctionne pour datatables d'exemple, mais s'il vous plaît tester avec plus de données que je viens de l'écrire rapidement.

Cela devrait fonctionner, Top 1 juste inséré pour la security, ne devrait pas être nécessaire si SDate et Id sont uniques en combinaison

 SELECT o.Id , ( SELECT TOP 1 Balance FROM tbl WHERE Id = o.Id AND SDate = MIN(o.SDate) ) Balance FROM tbl o GROUP BY Id HAVING sDate BETWEEN '20160101' AND '20160201'; 

Vous pouvez utiliser une sous-requête

 SELECT Id , ( SELECT TOP 1 Balance FROM [TableName] AS T1 WHERE T1.Id = [TableName].Id ORDER BY SDate ) AS Balance FROM [TableName] GROUP BY Id;