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
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;