56839


条件  
⓪ある１つのカラム(親テーブルの外部キー)の値ごとにデータを取得したい  
＋  
①現在日付より前の日付があれば最も新しい日付のレコードを抽出する  
②①に該当するものがなかった場合、現在日付よりも後の日付で最も古い日付のレコードを抽出する

上記のような条件で各外部キーのカラムごとに１レコードだけ抽出するようなクエリが書きたいのですが、  
現状以下に書いたクエリで、各外部キーごとに①もしくは②に合致するレコードを返すものを書いたのですが、この場合外部キーのカラムごとに最大2レコード返ってしまいます。この結果をプログラム側でやりくりすれば取りたいデータは取れなくはなさそうなのですが、  
INとサブクエリを利用しているのでパフォーマンスが悪そうなので、もっと上手い方法をご存知の方がいれば教えていただきたく、質問させていただきました。

ご回答よろしくお願いいたします。

[code]

    CREATE TABLE `parent` (
      `parent_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '親テーブルID'
    ) COMMENT='親テーブル';
    
    CREATE TABLE `child` (
      `child_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
      `switching_date` date NOT NULL COMMENT '切替日',
      `parent_id` int(10) unsigned NOT NULL COMMENT '親テーブルID'
    ) COMMENT='子テーブル';
    
[/code]

[code]

    SELECT * FROM child 
    WHERE 
    (
    (child.parent_id,child.switching_date) 
    IN (
    SELECT parent_id,MAX(switching_date) AS switching_date FROM child AS latest_child 
    WHERE latest_child.switching_date <= DATE_FORMAT(NOW(), '%Y%m%d')
    GROUP BY latest_child.parent_id
    ORDER BY switching_date DESC 
    ) 
    OR 
    (child.parent_id,child.switching_date) 
    IN (
    SELECT parent_id,MIN(switching_date) AS switching_date FROM child AS future_child 
    WHERE future_child.switching_date > DATE_FORMAT(NOW(), '%Y%m%d')
    GROUP BY future_child.parent_id
    ORDER BY switching_date DESC 
    )
    )
    GROUP BY child.parent_id,child.switching_date
    ORDER BY child.switching_date ASC ;
    
    
    
[/code]


CC BY-SA 4.0
2019-07-23T05:23:59.747
56835
2019-07-23T10:38:39.523
2019-07-23T10:38:39.523
34779
34779
question
mysql
mysqlのクエリにおいて、「①の結果がなければ、②の条件で探す」というような表現は可能でしょうか。


①と②の条件で親テーブルと[外部結合(SQL
Fiddle)](http://sqlfiddle.com/#!9/038440/1)して、[`ifnull`](https://dev.mysql.com/doc/refman/5.6/ja/control-
flow-functions.html#function_ifnull)で過去日がなければ未来日を表示する方法があります。

下記のサンプルSQLでは、`left
join`のwhere句で最新テーブルA(`PAST_A`)と未来テーブルA(`FUTURE_A`)を抽出しし、`ifnull`を使って過去日がなければ未来日を表示しています。

### サンプルSQL

[code]

    select   p.id as id,
             -- ifnullで ①最新テーブルの該当レコードがなければ②未来テーブルの該当レコードを表示
             ifnull(max(PAST_A.post_date), min(FUTURE_A.post_date)) as post_data
    from     PARENT P
             left join A PAST_A    -- 最新テーブルA
             on P.id = PAST_A.p_id and PAST_A.post_date < current_date()
             left join A FUTURE_A  -- 未来テーブルA
             on P.id = FUTURE_A.p_id and FUTURE_A.post_date >= current_date()
    group by p.id
    order by post_data asc
    
[/code]

### サンプルSQLのテーブル構成例

[code]

    create table PARENT (  -- 親テーブル
      id int primary key
    );
    
    create table A (
      id int,
      post_date date,  -- 日付カラム
      p_id int,        -- 親テーブル外部キーカラム
      foreign key (p_id) references PARENT(id)
    );
    
    insert into PARENT values(1);
    insert into PARENT values(2);
    insert into PARENT values(3);
    
    insert into A values(1, date_sub(current_date(), interval 1 day), 1);  -- 昨日
    insert into A values(2, date_sub(current_date(), interval 2 day), 1);  -- 一昨日
    
    insert into A values(3, date_add(current_date(), interval 1 day), 2);  -- 明日
    insert into A values(4, date_add(current_date(), interval 2 day), 2);  -- 明後日
    
    insert into A values(5, date_sub(current_date(), interval 1 day), 3);  -- 昨日
    insert into A values(6, current_date(), 3);                            -- 今日
    
[/code]


CC BY-SA 4.0
2019-07-23T07:57:17.920
56839
2019-07-23T07:57:17.920
9820
56835
answer