sql >> データベース >  >> RDS >> Mysql

PostgreSQL、MS SQL Server、およびMySQLでMOD()を使用して剰余を取得する方法

    問題:

    (負ではない)剰余を見つけたい。

    例:

    表のnumbers 、整数の2つの列があります: a およびb

    a b
    9 3
    5 3
    2 3
    0 3
    -2 3
    -5 3
    -9 3
    5 -3
    -5 -3
    5 0
    0 0

    aを除算して余りを計算したい bによる 。各余りは、 bよりも小さい非負の整数値である必要があります 。

    解決策1(完全に正しいわけではありません):

    SELECT
      a,
      b,
      MOD(a, b) AS remainder
    FROM numbers;
    

    結果は次のとおりです。

    a b 残り
    9 3 0
    5 3 2
    2 3 2
    0 3 0
    -2 3 -2
    -5 3 -2
    -9 3 0
    5 -3 2
    -5 -3 -2
    5 0 エラー
    0 0 エラー

    ディスカッション:

    aが負でない場合、このソリューションは正しく機能します。ただし、負の場合は、余りの数学的定義に従いません。

    概念的には、剰余は aの整数除算の後に残るものです。 bによる 。数学的には、2つの整数の余りは、除数 bよりも小さい非負の整数です。 。より正確には、それは数r∈{0,1、...、 b -1} a =k * b + rのような整数kが存在する 。例:

    5 =1 * 3 + 2 、したがって、5と3の余りは 2に等しくなります 。

    9 =3 * 3 + 0 、したがって、9と3の余りは 0に等しくなります 。

    5 =(-1)*(-3)+ 2 、したがって、5と-3の余りは 2に等しくなります 。

    これがMOD(a、b)の方法です a列の負でない配当に対して機能します 。明らかに、除数が b の場合、エラーが表示されます。 0です 、 0で除算できないため 。

    被除数aが負の数の場合、正しい剰余を取得することは問題があります。残念ながら、 MOD(a、b) aが負の場合、負の値を返すことができます。例:

    MOD(-2、5) -2を返します 3を返す必要がある場合 。

    MOD(-5、-3) -2を返します 1を返す必要がある場合 。

    解決策2(すべての数値に対して正しい):

    SELECT
      a,
      b,
      CASE WHEN MOD(a, b) >= 0
        THEN MOD(a, b)
      ELSE
        MOD(a, b) + ABS(b)
      END AS remainder
    FROM numbers;
    

    結果は次のとおりです。

    a b 残り
    9 3 0
    5 3 2
    2 3 2
    0 3 0
    -2 3 1
    -5 3 1
    -9 3 0
    5 -3 2
    -5 -3 1
    5 0 エラー
    0 0 エラー

    ディスカッション:

    任意間の除算の余りを計算するには 2つの整数(負または非負)の場合、 CASE WHENを使用できます 工事。 MOD(a、b)の場合 は負ではなく、余りは単純に MOD(a、b) 。それ以外の場合は、 MOD(a、b)によって返される結果を修正する必要があります 。

    MOD()の場合、どのようにして正しい余りを取得しますか 負の値を返しますか?除数の絶対値をMOD(a、b)に追加する必要があります 。つまり、 MOD(a、b)+ ABS(b)にします。 :

    MOD(-2、5) -2を返します 3を返す必要がある場合 。これを修正するには、 5を追加します 。

    MOD(-5、-3) -2を返します 1を返す必要がある場合 。これは、 3を追加することで修正できます 。

    MOD(a、b)の場合 負の数、 CASE WHENを返します 結果はMOD(a、b)+ ABS(b)になります 。これがソリューション2の取得方法です。ABS()の方法について復習が必要な場合 関数が機能する場合は、クックブック「SQLで絶対値を計算する方法」を参照してください。

    もちろん、数値を 0で割ることはできません。 。したがって、 b =0の場合 、エラーが発生します。

    解決策3(すべての数値に対して正しい):

    SELECT
      a,
      b,
      MOD(a, b) + ABS(b) * (1 - SIGN(MOD(a, b) + 0.5)) / 2 AS remainder
    FROM numbers;
    

    結果は次のとおりです。

    a b 残り
    9 3 0
    5 3 2
    2 3 2
    0 3 0
    -2 3 1
    -5 3 1
    -9 3 0
    5 -3 2
    -5 -3 1
    5 0 エラー
    0 0 エラー

    ディスカッション:

    この問題を解決する別の方法があります。 CASE WHENの代わりに 、より複雑な1行の数式を使用します:

    MOD(a、b)+ ABS(b)*(1-SIGN(MOD(a、b)+ 0.5))/ 2

    ソリューション2では、 MOD(a、b)+ ABS(b) MOD(a、b)<0の場合に返されました 。 MOD(a、b)<0 の場合、 MOD(a、b)+ ABS(b)=MOD(a、b)+ ABS(b)*1であることに注意してください。 。

    対照的に、 MOD(a、b)を返します。 MOD(a、b)> =0の場合 。 MOD(a、b)=MOD(a、b)+ ABS(b)* 0(MOD(a、b)> =0の場合)

    したがって、 ABS(b)を乗算できます。 負のMOD(a、b)の場合は1に等しい式によって および0 非負のMOD(a、b)の場合 。 MOD(a、b)以降 は常に整数であり、式 MOD(a、b)+ 0.5 MOD(a、b)≥0の場合は常に正です MOD(a、b)<0の場合は負 。 1未満の任意の正の数を使用できます 0.5の代わりに 。

    符号関数SIGN() 1を返します 引数が厳密に正の場合、 -1 厳密に負の場合、 0 0に等しい場合 。ただし、 0のみを返すものが必要です。 および1 1ではありません および-1 。これを修正する方法は次のとおりです。

    (1-1)/ 2 =0

    (1-(-1))/ 2 =1

    次に、 ABS(b)を乗算する正しい式 は:

    (1-SIGN(MOD(a、b)+ 0.5))/ 2

    したがって、式全体は次のようになります。

    MOD(a、b)+ ABS(b)*(1-SIGN(MOD(a、b)+ 0.5))/ 2


    1. pgDash DiagnosticsAlternatives-ClusterControlを使用したPostgreSQLクエリ管理

    2. sqliteデータベースで日付を並べ替えますか?

    3. Ubuntu16.04にMySQLWorkbenchをインストールして構成する

    4. SQLServerの統計の改善にご協力ください。