20

ストリームの次のスケジュールされたアイテムを取得するために、次のselectステートメントがあります。一致する行がない場合は、デフォルト値を返すようにします。これが私が使用しているSQLです:

SELECT `file`
FROM `show`, `schedule` 
WHERE `channel` = 1
  AND `start_time` <= UNIX_TIMESTAMP() 
  AND `start_time` > UNIX_TIMESTAMP()-1800
  AND `show`.`id` = `schedule`.`file` 
ORDER BY `start_time`
DESC LIMIT 1

これにより、最後にスケジュールされたアイテムが取得されますが、クエリの30分前より古い場合は取得されません。

ただし、ユーザーが何もスケジュールしない場合は、デフォルト値が必要です。これにより、実際にストリームで何かが再生されます。私は次のことを試しました:

SELECT COALESCE(`file`, 'default.webm')
FROM `show`, `schedule`...

SELECT IFNULL(`file`, 'default.webm')
FROM `show`, `schedule`

ただし、行が見つからない場合は常に空の結果を返します。代わりにデフォルト値を返すにはどうすればよいですか?

4

3 に答える 3

27

それを行う1つの方法

SELECT IFNULL(MIN(`file`), 'default.webm') `file` 
  FROM `show`, `schedule` 
 WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP() 
   AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file` 
 ORDER BY `start_time` DESC LIMIT 1

返される行は1つだけなので、集計関数を使用できます。この場合、レコードが選択されていない場合MIN()でも確実に取得できます。NULLその後IFNULL()、またはCOALESCE()その仕事をします。

于 2013-03-10T05:37:43.577 に答える
15

@petermの回答とこの回答は、結果セットで最大1行を返すSQLロジックに対応するように設計されています。

彼の答えは、単一の列を持つ単一の行を返すように設計されています。

私の答えは、1つ以上の列を持つ単一の行を返すように設計されています。

基本的に、最初のSELECTと同じ列数を持つUNION2番目の句でハードコードされた値を使用できます。SELECT

OPの場合:

(
    SELECT `file`
    FROM `show`,
         `schedule` 
    WHERE `channel` = 1
      AND `start_time` BETWEEN UNIX_TIMESTAMP()-1799 AND UNIX_TIMESTAMP() 
      AND `show`.`id` = `schedule`.`file` 
    ORDER BY `start_time` DESC
    LIMIT 1
) UNION (
    SELECT 'default.webm'
)
ORDER BY file = 'default.webm'
LIMIT 1;

構文エラーがなければ、結果セットは、1つの列が。としてキー設定された1つの行を提供しますfile


より一般的な例として:(DB-Fiddle Demo

(
    SELECT Col1,Col2,Col3
    FROM ExampleTable
    WHERE ID='1234'
) UNION (
    SELECT 'Def Val','none',''
)
ORDER BY Col1 = 'Def Val'
LIMIT 1;

結果:

  • 最初のSELECTに行が見つからない場合、結果セットには2番目のSELECTの値が入力されます。配列としての結果セットは次のようになります。

    [['Col1' => 'Def Val', 'Col2' => 'none', 'Col3' => '']]
    
  • 最初のSELECTで1つの行が見つかった場合、最初のSELECT値が結果セットに提供され、2番目のSELECT値は省略されます。結果セットは次のようになります:(私のデモリンクを参照)

    [['Col1' => 'A', 'Col2' => 'B', 'Col3' => 'C']]
    

*結果セットの連想キーは、最初のSELECTクエリの列名/エイリアスによって決定されます。

*後続のSELECTクエリでは、列エイリアスを指定する必要はありません。

* UNIONでは、2つの統合クエリの列名が同一である必要はありません。実際、後続のSELECTクエリの列名またはデータソースは何でもかまいません(異なる列、関数呼び出しなど)。

(
    SELECT Col1,Col2,Col3
    FROM ExampleTable
    WHERE ID='1234'
) UNION (
    SELECT 'Def Val' AS `Fallback1`,
           'none'    AS `Fallback2`,
           ''        AS `Fallback3`
)
ORDER BY Col1 = 'Def Val'
LIMIT 1;

私の意見では、これは非常に読みやすく、負担のかかる質問のようには思えません。


UNIONによって生成された行の順序に関する潜在的なバグを見つけてくれた@LudovicKutyに感謝します。https://dev.mysql.com/doc/refman/8.0/en/union.html#union-order-by-limit見つかった行の前にデフォルトの行が順序付けられる可能性を排除するには、次のようにORDERBY句を記述します。デフォルトの行が常に結果セットの後半で順序付けられるようにするための十分なロジック。デフォルトの行を識別するために使用できるさまざまなsql-dialect固有の構文があります。いくつかORDER BY columnName = 'default value'は十分であり、他はorまたはorなどを要求するかもしれませんIFIIFデフォルトCASEが真の結果を返すようにロジックを構築する限り、trueはとして扱われ1、falseはとして扱われます0-そしてもちろん1後になります0昇順で並べ替える場合。

于 2016-01-13T04:51:28.303 に答える
0

さまざまなケースを処理するには、いくつかの条件付きロジックが必要になります。これはMySQLのストアドプロシージャでのみ使用できるため、このコードをプロシージャでラップして呼び出す必要があります。

if exists (
       SELECT `file` FROM `show`, `schedule` 
       WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP() 
       AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file` 
) then
       SELECT `file` FROM `show`, `schedule` 
       WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP() 
       AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file` 
       ORDER BY `start_time` DESC LIMIT 1
; else
        select `DefaultValue` as `file`
; end if
于 2015-10-08T13:48:43.400 に答える