2
votes

Sélection des lignes avec la date la plus élevée

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.


4 commentaires

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 MAX renverrait les mauvaises valeurs; comme le prix 1.25 pour la date 03/01/2018 sur ID 1 .


3 Réponses :


0
votes

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


0 commentaires

2
votes

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


5 commentaires

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.



1
votes

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


0 commentaires