Od dawna próbuję to rozgryźć, ale zaczynam się poddawać.
Aby uprościć sprawę, powiedzmy, że mam 2 tabele. Główny stół to articles
i pozostaję przy dołączaniu do tego contracts
. Tabela umów ma datę końcową. Chcę tylko wybrać 1 (jeden) wiersz z tego artykułu, wybierając najnowszy contract_to
data.
Próbowałem już spróbować czegoś takiego LEFT JOIN contracts ON (contracts.article = articles.id) ORDER BY contract_to DESC LIMIT 1
ale oczywiście to nie działa.
Jak mam to zrobić?
Należy udawać, że zakresy dat dla każdego wiersza w poniższej tabeli są różne.
Również ostatnia data nie jest taka sama dla wszystkich umów na artykuły, więc nie mogę po prostu określić, co jest najnowszą datą, a następnie umieścić ją w klauzuli WHERE.
Odpowiedzi:
3 dla odpowiedzi № 1Aby uzyskać najnowsze contract_to
wartość, będziesz potrzebować MAX()
agregat. Właściwym sposobem na to jest użycie sprzężenia podkwerendy, aby uzyskać tylko article
i MAX(contract_to)
wartości, a następnie połącz je z pozostałymi wartościami wiersza. Wreszcie, całą strukturę można połączyć z articles
stół.
SELECT
articles.*,
contracts.*
FROM
articles
/* Join against a subquery which returns only the article and latest contract_to */
LEFT JOIN (
SELECT article, MAX(contract_to) AS contract_to
FROM contracts
GROUP BY article
) maxcontract ON articles.article_id = maxcontract.article
/* and join that against the rest of the contracts table, on those two column values */
JOIN contracts
ON maxcontract.article = contracts.article
AND maxcontract.contract_to = contracts.contract_to
Ponieważ MySQL jest łagodny w stosunku do zawartości GROUP BY
klauzula ta metoda może nie być konieczna, łącząc się oddzielnie z contracts
table, i prawdopodobnie mógłbyś to zrobić z samym podzapytaniem, ale to nie zadziałało w większości innych RDBMS i jest to naprawdę dobry sposób na zrobienie tego bez polegania na dziwnym zachowaniu MySQL.
1 dla odpowiedzi nr 2
MySQL nie ma ładnych funkcji analitycznych, które oferują niektóre systemy DBMS, ale możesz napisać (na przykład):
SELECT ...
FROM articles
LEFT
OUTER
JOIN ( SELECT article,
MAX(contract_to) AS contract_to
FROM contracts
GROUP
BY article
) articles_to_max_contracts
ON articles_to_max_contracts.article = articles.id
LEFT
OUTER
JOIN contracts
ON contracts.article = articles.id
AND contracts.contract_to = articles_to_max_contracts.contract_to
;
0 dla odpowiedzi № 3
Aby uzyskać tylko cenę, możesz to zrobić również ze skorelowanym podzapytaniem:
select a.*,
(select price
from contracts c
where a.article = c.article
order by contract_from desc
limit 1
) as lastPrice
from articles a;
Z indeksem na contracts(article, contract_from)
powinno to być nawet względnie wydajne.