Zapytanie, aby uzyskać wszystkie wiersze z poprzedniego miesiąca


90

Muszę zaznaczyć wszystkie wiersze w mojej bazie danych, które zostały utworzone w zeszłym miesiącu.

Na przykład, jeśli bieżącym miesiącem jest styczeń, chcę zwrócić wszystkie wiersze utworzone w grudniu, jeśli miesiącem jest luty, chcę zwrócić wszystkie wiersze utworzone w styczniu. Mam date_createdkolumnę w mojej bazy danych, która zawiera wykaz dat tworzone w tym formacie: 2007-06-05 14:50:17.

Odpowiedzi:


198
SELECT * FROM table
WHERE YEAR(date_created) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(date_created) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)

70
SELECT * FROM table WHERE date_created BETWEEN (CURRENT_DATE() - INTERVAL 1 MONTH) AND CURRENT_DATE();
Ghazanfar Mir

12
@GhazanfarMir Twoje zapytanie nie pasuje do pytania, podczas gdy powyższa odpowiedź tak. Twój zwraca wiersze między tym dniem ostatniego miesiąca a wczoraj.
Matt Passell,

@MattPassell Przykro mi, ale betweenobejmuje granice .. Będzie zawierać również aktualną datę. Dlaczego / jak to będzie ograniczone do wczoraj ?? Proszę rozwinąć?
Ghazanfar Mir

4
Rozumiem, co masz na myśli .. Tak masz rację .. moje zapytanie nie jest to, co PO chciała .. I źle na pytanie
Ghazanfar Mir

a co jeśli current_dateto nie dzisiaj, a przypadkowa data podana przez klienta?
dios231

22

Oto inna alternatywa. Zakładając, że masz pole indeksowane DATElub DATETIMEpole typu, należy użyć indeksu, ponieważ sformatowane daty zostaną przekonwertowane na typ przed użyciem indeksu. Po wyświetleniu za pomocą EXPLAIN powinieneś zobaczyć rangezapytanie, a nie indexzapytanie .

SELECT
    * 
FROM
    table
WHERE 
    date_created >= DATE_FORMAT( CURRENT_DATE - INTERVAL 1 MONTH, '%Y/%m/01' ) 
AND
    date_created < DATE_FORMAT( CURRENT_DATE, '%Y/%m/01' )

+1. Znacznie bardziej przyjazny dla indeksów. Możesz także rzucić STR_TO_DATEwokół, DATE_FORMATwięc zawsze ma do czynienia z obiektami daty.
Leigh

14

Jeśli nie ma przyszłych dat ...

SELECT * 
FROM   table_name 
WHERE  date_created > (NOW() - INTERVAL 1 MONTH);

Przetestowany.


3
Myślę, że szukali czegoś innego. tj. Wszystkie rekordy z ostatniego miesiąca (tj. 1 października - 31 października 2012 23:59:59). Powyższe zapytanie zwróci ostatnie ~ 30 dni od dzisiejszej daty i godziny .
Leigh,

13

Alternatywnie do odpowiedzi hobodave

SELECT * FROM table
WHERE YEAR(date_created) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(date_created) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)

Możesz osiągnąć to samo z EXTRACT, używając YEAR_MONTH jako jednostki, więc nie potrzebujesz AND, na przykład:

SELECT * FROM table
WHERE EXTRACT(YEAR_MONTH FROM date_created) = EXTRACT(YEAR_MONTH FROM CURDATE() - INTERVAL
1 MONTH)

Działa to świetnie przez miesiące, ale niestety nie ma YEAR_WEEK odstępu czasowego , więc musiałbyś wrócić do odpowiedzi hobodave, jeśli potrzebujesz tygodni zamiast miesięcy.
Danny Beckett

8
SELECT *
FROM  yourtable
where DATE_FORMAT(date_created, '%Y-%m') = date_format(DATE_SUB(curdate(), INTERVAL 1 month),'%Y-%m')

Powinno to zwrócić wszystkie rekordy z poprzedniego miesiąca kalendarzowego, w przeciwieństwie do zapisów z ostatnich 30 lub 31 dni.


Zapomniałem wspomnieć ... to powinno zwrócić wszystkie rekordy z poprzedniego miesiąca kalendarzowego, w przeciwieństwie do zapisów z ostatnich 30 lub 31 dni.
Gregg

Moim zdaniem powinna to być akceptowana odpowiedź, ponieważ jest prostsza niż zaakceptowana odpowiedź, ale daje ten sam wynik
Grant

3

Mimo że odpowiedź na to pytanie została już wybrana, wydaje mi się, że najprostsze będzie zapytanie

SELECT * 
FROM table 
WHERE 
date_created BETWEEN (CURRENT_DATE() - INTERVAL 1 MONTH) AND CURRENT_DATE();

2
Nie, niezupełnie. Zobacz moją odpowiedź na Twój komentarz na temat odpowiedzi udzielonej przez @hobodave
Matt Passell

@MattPassell Masz rację, źle zrozumiałem pytanie .. Nie zrozumiałem, że wynik powinien ograniczać się tylko do rekordów TYLKO z zeszłego miesiąca.
Ghazanfar Mir

2
WHERE created_date >= DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY) 
  AND created_date <= DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 1 MONTH)), INTERVAL 0 DAY) 

To zadziałało dla mnie (wybiera wszystkie rekordy utworzone w zeszłym miesiącu, niezależnie od dnia uruchomienia zapytania w tym miesiącu)


1

select fields FROM table WHERE date_created LIKE concat(LEFT(DATE_SUB(NOW(), interval 1 month),7),'%');

ten będzie mógł skorzystać z indeksu, jeśli data_created jest indeksowana, ponieważ nie stosuje żadnej funkcji transformacji do wartości pola.


@ggiroux - Przed zastosowaniem LIKE musi jednak przekonwertować datę na typ znaku.
Martin Clayton

tak rzeczywiście, ale nadal poprawa w stosunku do wybranej odpowiedzi IMHO (indeksowany jest IFF date_created)
ggiroux

1

Oto zapytanie, aby uzyskać rekordy z ostatniego miesiąca:

SELECT *
FROM `tablename`
WHERE `datefiled`
BETWEEN DATE_SUB( DATE( NOW( ) ) , INTERVAL 1
MONTH )
AND 
LAST_DAY( DATE_SUB( DATE( NOW( ) ) , INTERVAL 1
MONTH ) )

Pozdrawiam - saqib


Czy próbowałeś uruchomić to zapytanie? O ile widzę, nie zaznaczyłby wszystkich dat z poprzednich miesięcy (np .: dane zwrotne ze stycznia przez cały luty), ale zwróciłby dane z zakresu rozpoczynającego się tego samego dnia miesiąc temu
Nico Haase

0

Alternatywa z jednym warunkiem

SELECT * FROM table
WHERE YEAR(date_created) * 12 + MONTH(date_created)
    = YEAR(CURRENT_DATE) * 12 + MONTH(CURRENT_DATE) - 1

-1
SELECT *  FROM table  
WHERE  YEAR(date_created) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(date_created) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)

Czy próbowałeś uruchomić to zapytanie? O ile widzę, nie zaznaczyłby wszystkich dat z poprzednich miesięcy (np .: dane zwrotne ze stycznia przez cały luty), ale zwróciłby dane z zakresu rozpoczynającego się tego samego dnia miesiąc temu
Nico Haase

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.