0

今日の日付の前後 3 日間の誕生日を持つユーザーのリストを取得したいと考えています。つまり、今日が の場合、誕生日がまでMarch 2,2013のユーザーを取得したいということです。これが私のデータベース設計です。Feb 27,2013March 5,2013

ユーザー テーブル

id | name | birth_day | birth_month | birth_year

データベースにアクセスできないため、データベースのデザインを変更することはできなくなりました。デザインの変更は、Web サイトの大幅な変更にのみ発生します。

これは私の現在のコードです:

if (empty($date))
            $date = date('Y-m-d'); // now

        $start_date = strtotime($date.' -'.$day_range.' day');
        $end_date = strtotime($date.' +'.$day_range.' day');
        $start_month = date('m', $start_date);
        $end_month = date('m', $end_date);
        $start_day = date('d', $start_date);
        $end_day = date('d', $end_date);

        if ($start_day > $end_day) {
            $tmp = $start_day;
            $start_day = $end_day;
            $end_day = $tmp;
        }

        /* This is a dirty fix for getting birthdays between dates */
        $this->User->contain(array('User' => array('first_name', 'last_name', 'userstatus_id')));
        $user = $this->User->find('all', array(
            'conditions' => array(
                'User.birth_month BETWEEN ? AND ?' => array($start_month, $end_month),
                'User.birth_day BETWEEN ? AND ?' => array($start_day, $end_day),
            ),
            'fields' => array(
                'birth_year',
                'birth_day',
                'birth_month'
            ),
            'order' => array(
                'birth_month' => 'ASC',
                'birth_day' => 'ASC'
            )
        ));

        foreach($user as $k => $v) {
            $temp = strtotime(date('Y-'.$user[$k]['User']['birth_month'].'-'.$user[$k]['User']['birth_day']));

            if ($temp >= $start_date && $temp <= $end_date) {
            }
            else {
                unset($user[$k]);
            }

        }
4

2 に答える 2

5

テーブルのデザインを変更できない場合は、3 つの列から日時を作成し、それをフィルターに使用します。

select *
from 
(
  select id, name,
    str_to_date(concat(year(now()), '-', birth_month, '-', birth_day), '%Y-%m-%d') birthdate
  from users
) d
where birthdate >= '2013-02-27'
  and birthdate <= '2013-03-05'

SQL Fiddle with Demoを参照してください。

これは、関数STR_TO_DATE()CONCAT()関数を使用して、生年月日を日付データ型として作成します。日付を取得したら、日付フィルターを適用できます。

于 2013-03-01T16:11:20.443 に答える
0

アルファベット順に日付を取得する必要があるため、年、月、日をクエリします。問題は、月初と月末の重複です。MySQL の日付フォーマット オプションを使用すると、日付を連結し、それらを日付オブジェクトに変換して検索することができます。多くの行がある場合、すべての行を評価する必要があるため、これは遅くなり、効率的ではありません。

もう 1 つの方法は、既にある列に対してクエリを実行することですが、アプリケーション ロジックから導き出された範囲条件を使用して、次のようなインライン SQL を生成します。

SELECT * FROM users
WHERE 1=1

それで:

AND birth_year = X

重複する範囲の場合は OR

AND (birth_year = X OR birth_year = Y)

誕生月と誕生日も同様に

洗練されたソリューションではありませんが、スキーマ設計が貧弱であるため、これら 2 つの選択肢のうちの 1 つしかわかりません。最初のほうが簡単ですが、クエリが完全なテーブル スキャンを実行しない場合は、通常、2 番目の方がパフォーマンスが向上します。インデックスを作成していない場合は、string to date オプションを使用してください。

于 2013-03-01T16:19:46.980 に答える