J'ai une table de données (la base de données est MSSQL):
ID OrderNO PartCode Quantity DateEntered
417 2144 44917 100 18-08-11
418 7235 11762 5 18-08-11
419 9999 60657 100 18-08-11
420 9999 60657 90 19-08-11
Je voudrais faire une requête qui retourne OrderNO, PartCode et Quantity, mais seulement pour la dernière commande enregistrée.
Dans l'exemple de la table, j'aimerais récupérer les informations suivantes:
OrderNO PartCode Quantity
2144 44917 100
7235 11762 5
9999 60657 90
Notez que seule une ligne a été renvoyée pour la commande 9999.
Merci!
Si rownumber() over(...)
est disponible pour vous ....
select OrderNO,
PartCode,
Quantity
from (select OrderNO,
PartCode,
Quantity,
row_number() over(partition by OrderNO order by DateEntered desc) as rn
from YourTable) as T
where rn = 1
Le meilleur moyen est Mikael Eriksson, si ROW_NUMBER()
est à votre disposition.
La meilleure solution consiste à rejoindre une requête, selon la réponse de Cularis.
La solution la plus simple et la plus simple consiste à utiliser une sous-requête corrélée dans la clause WHERE.
SELECT
*
FROM
yourTable AS [data]
WHERE
DateEntered = (SELECT MAX(DateEntered) FROM yourTable WHERE orderNo = [data].orderNo)
Ou...
WHERE
ID = (SELECT TOP 1 ID FROM yourTable WHERE orderNo = [data].orderNo ORDER BY DateEntered DESC)
select OrderNo,PartCode,Quantity
from dbo.Test t1
WHERE EXISTS(SELECT 1
FROM dbo.Test t2
WHERE t2.OrderNo = t1.OrderNo
AND t2.PartCode = t1.PartCode
GROUP BY t2.OrderNo,
t2.PartCode
HAVING t1.DateEntered = MAX(t2.DateEntered))
C'est la plus rapide de toutes les requêtes fournies ci-dessus. Le coût de la requête s'élevait à 0,0070668.
La réponse préférée ci-dessus, de Mikael Eriksson, a un coût de requête de 0,0146625.
Vous ne vous souciez peut-être pas de la performance d’un échantillon aussi petit, mais dans les requêtes volumineuses, tout s’ajoute.
SELECT t1.OrderNo, t1.PartCode, t1.Quantity
FROM table AS t1
INNER JOIN (SELECT OrderNo, MAX(DateEntered) AS MaxDate
FROM table
GROUP BY OrderNo) AS t2
ON (t1.OrderNo = t2.OrderNo AND t1.DateEntered = t2.MaxDate)
La requête interne sélectionne toutes les OrderNo
avec leur date maximale. Pour obtenir les autres colonnes de la table, vous pouvez les joindre sur OrderNo
et la MaxDate
.
rownumber () over (...) fonctionne mais je n'ai pas aimé cette solution pour 2 raisons . - Cette fonction n'est pas disponible lorsque vous utilisez une version antérieure de SQL telle que SQL2000 - La dépendance à la fonction et n'est pas vraiment lisible.
Une autre solution est:
SELECT tmpall.[OrderNO] ,
tmpall.[PartCode] ,
tmpall.[Quantity] ,
FROM (SELECT [OrderNO],
[PartCode],
[Quantity],
[DateEntered]
FROM you_table) AS tmpall
INNER JOIN (SELECT [OrderNO],
Max([DateEntered]) AS _max_date
FROM your_table
GROUP BY OrderNO ) AS tmplast
ON tmpall.[OrderNO] = tmplast.[OrderNO]
AND tmpall.[DateEntered] = tmplast._max_date
Et vous pouvez également utiliser cette instruction select en tant que requête de jointure gauche ... Exemple:
... left join (select OrderNO,
PartCode,
Quantity from (select OrderNO,
PartCode,
Quantity,
row_number() over(partition by OrderNO order by DateEntered desc) as rn
from YourTable) as T where rn = 1 ) RESULT on ....
J'espère que cela aidera quelqu'un qui cherche cela :)
Si vous avez indexé ID et OrderNo, vous pouvez utiliser IN: (je déteste la simplicité de négociation pour des raisons d'obscurité, juste pour économiser quelques cycles):
select * from myTab where ID in(select max(ID) from myTab group by OrderNo);
Pour MySql, vous pouvez effectuer les opérations suivantes:
select OrderNO, PartCode, Quantity from table a
join (select ID, MAX(DateEntered) from table group by OrderNO) b on a.ID = b.ID
Essayez d'éviter d'utiliser IN JOIN
SELECT SQL_CALC_FOUND_ROWS * FROM (SELECT msisdn, callid, Change_color, play_file_name, date_played FROM insert_log
WHERE play_file_name NOT IN('Prompt1','Conclusion_Prompt_1','silent')
ORDER BY callid ASC) t1 JOIN (SELECT MAX(date_played) AS date_played FROM insert_log GROUP BY callid) t2 ON t1.date_played=t2.date_played