J'ai la requête suivante qui renvoie un résultat comme dans l'exemple:
IdArt IdAdr gDate Price 1 10 03/01/2018 1.18 2 15 01/01/2018 1.03 2 18 10/01/2018 0.12 3 25 28/01/2018 1.99 4 30 15/01/2018 2.55 5 35 08/01/2018 0.11
Le résultat final que je veux est:
- Lorsque l'IdArt et l'IdAdr sont identiques, il ne doit y avoir qu'une seule ligne avec la date la plus élevée de toutes les lignes (CASE IdArt 1)
- Lorsque l'IdArt est identique mais que l'IdAdr est différent, il doit y avoir une ligne avec chaque IdAdr avec la date la plus élevée pour chaque IdAdr. (CASE IdArt 2)
- Le prix n'affecte rien.
Donc, la table finale que j'aimerais avoir est:
SELECT P.IdArt, P.IdAdr, P.gDate, P.Price
FROM dbo.T_PriceData AS P INNER JOIN
dbo.T_Adr AS A ON P.IdAdr = A.IdAdr INNER JOIN
dbo.T_Stat AS S ON A.IdStat = S.IdStat
GROUP BY P.IdArt, P.IdAdr, P.gDate, P.Price
IdArt IdAdr gDate Price
1 10 01/01/2018 1.25
1 10 02/01/2018 1.17
1 10 03/01/2018 1.18
2 15 01/01/2018 1.03
2 18 10/01/2018 0.12
3 25 12/01/2018 0.98
3 25 28/01/2018 1.99
4 30 15/01/2018 2.55
5 35 08/01/2018 0.11
Comment puis-je faire cela? J'ai essayé avec une clause de sélection par MAX (gDate) mais, bien sûr, je n'obtiens qu'une seule ligne avec la date maximale de toute la base de données.
3 Réponses :
Vous pouvez utiliser ROW_Number():
SELECT q.IdArt , q.IdArt , q.IdADr , q.gDate , q.Price FROM ( SELECT t.IdArt , t.IdADr , t.gDate , t.Price , ROW_NUMBER() OVER (PARTITION BY t.IdArt, t.IdADr ORDER BY t.gDate DESC) rn FROM dbo.T_PriceData t ) q WHERE q.rn = 1
Il y a beaucoup de réponses sur la façon de faire cela, cependant, cela vous permet d'obtenir ce que vous recherchez:
SELECT TOP 1 WITH TIES
P.IdArt,
P.IdAdr,
P.gDate,
P.Price
FROM dbo.T_PriceData P
WHERE EXISTS (SELECT 1
FROM dbo.T_Adr A
WHERE P.IdAdr = A.IdAdr)
AND EXISTS (SELECT 1
FROM dbo.T_Stat S
WHERE A.IdStat = S.IdStat)
ORDER BY ROW_NUMBER() OVER (PARTITION BY P.IdArt, P.IdAdr ORDER BY P.gDate DESC);
Modifier: si le JOIN s sont là pour s'assurer qu'il y a des lignes dans les autres tables, alors selon les commentaires, j'utiliserais EXISTS . Si vous utilisez simplement JOIN et que vous ne renvoyez que les lignes de la première table, vous risquez de vous retrouver avec des lignes en double.
SELECT TOP 1 WITH TIES
P.IdArt,
P.IdAdr,
P.gDate,
P.Price
FROM dbo.T_PriceData P
--INNER JOIN dbo.T_Adr A ON P.IdAdr = A.IdAdr --You don't reference this in the SELECT or WHERE. Why is it here?
--INNER JOIN dbo.T_Stat S ON A.IdStat = S.IdStat --You don't reference this in the SELECT or WHERE. Why is it here?
ORDER BY ROW_NUMBER() OVER (PARTITION BY P.IdArt, P.IdAdr ORDER BY P.gDate DESC);
Le INNER JOIN est la condition que cette ligne ait une référence dans ces deux autres tables. Vous ne pouvez l'omettre que s'il s'agit d'un LEFT JOIN . Ou peut-être que je me trompe, et la requête elle-même n'avait pas cette intention ...
Personnellement, j'irais avec un EXISTS puis @ PhamX.Bach. Sinon, s'il s'agit de relations plusieurs à un, vous pourriez vous retrouver avec plusieurs lignes en double.
Non, cela n'aidera peut-être pas ici @ RadimBača, car vous auriez alors plusieurs lignes pour la même date. Le PO n'en veut qu'un.
Le premier semble fonctionner correctement. Juste pour que je comprenne ... qu'est-ce que la clause "WITH TIES" là-bas?
Il fait ce que cela implique en vérité. En cas d'égalité, toutes les lignes de liaison sont renvoyées. Dans ce cas, où la valeur de ROW_NUMBER est 1, @Nanaki.
Vous voulez la date la plus élevée pour chaque combinaison IdArt / IdAdr . Les fonctions de fenêtre sont tentantes, mais la méthode la plus efficace est souvent une sous-requête corrélée.
Votre requête ne sélectionne que dans T_PriceData , donc le reste de la requête (les jointures et groupent par ) ne semblent pas nécessaires - à moins que les jointures filtrent les données, ce qui semble peu probable car les jointures font référence à des tables.
Je recommanderais donc:
SELECT P.IdArt, P.IdAdr, P.gDate, P.Price
FROM dbo.T_PriceData P
WHERE P.gDate = (SELECT MAX(P2.gDate)
FROM dbo.T_PriceData P2
WHERE P2.IdArt = P.IdArt AND
P2.IAdr = P.IdAdr
);
Votre première exigence n'est-elle pas déjà fournie par votre deuxième? N'est-ce pas simplement "chaque combinaison unique d'idArt et d'idAdr devrait produire une ligne de sortie"?
Indice:
MAX (gDate), MAX (Price) ... GROUP BY IdArt, IdAdr@Sami c'est une question populaire d'obtenir des lignes avec max dans une colonne. Généralement, il va dans un
() IN ();INNER JOIN max_table; ....MAX (prix)ne devrait pas fonctionner.@Sami utilisant
MAXrenverrait les mauvaises valeurs; comme le prix1.25pour la date03/01/2018surID1.