2

私はテーブルを持っています:

   c1|c2|c3|c4
-----+--+--+----    
    a  b c  10
    a  a b  20
    c  a c  10
    b  b c  10
    c  b c  30

入力が3つの文字列/テキストである関数を作成したい. ) カラムアップ。しかし、 bacまたはcabの星座がある場合、abc 10 に一致します。bccのような行がある場合、 cbbのような行にはなりません。すべての対戦はユニークです。

string_to_array(text, text) を使用するのが最善だと思います。

疑似コードをいくつかまとめましたが、SQL での記述方法がわかりません。ロジックも間違っているかもしれません。

function (x,y,z)
 res = 0
 x_array = string_to_array(x, ' ')
 y_array = string_to_array(y, ' ')
 z_array = string_to_array(z, ' ')

 foreach(x_item in x_array)
  foreach(y_item in y_array)
   foreach(z_item in z_array)
    if  (c1 = (x_item || y_item || z_item ) && c2 = (x_item || y_item || z_item ) && c3 = (x_item || y_item || z_item ))
     res++

編集

  • まず、例の表に誤りがありました。行abccbaがありました。それはできません。abc = cba ! 各行は一意である必要があります。
  • 例: 3 つのテキスト入力 abc | 紀元前| c
  • 各要素と各要素: abc、acc、bbc、bcc、cbc、ccc
  • abc = 10; acc ( cacと同じ) = 10; bbc = 10; bcc ( cbcと同じ) = 30; cbc = 30; ccc (一致なし) = 0; 結果 = 90
4

2 に答える 2

2

これはあなたが望むものかもしれないと思います:

c4指定された 3 つのトークンのセットが列と一致するすべての行から、列の合計を返します(c1, c2, c3)

シンプルバージョン

contains@>および is included <@by 演算子を使用すると、はるかに簡単になります。

SELECT sum(c4) AS sum_of_matching_c4
FROM   tbl
WHERE  ARRAY[c1,c2,c3] <@ ARRAY['b', 'a', 'c'] -- strings in arbitrary order
AND    ARRAY[c1,c2,c3] @> ARRAY['b', 'a', 'c'];

申し訳ありませんが、それは('b', 'c', 'c')vs.では失敗し('c', 'b', 'b')ます。

ゆっくり確実に

WITH i(arr) AS (
   SELECT ARRAY(VALUES ('b'), ('c'), ('c') ORDER BY 1)  -- input once
   )                                                    -- in arbitrary order
SELECT sum(c4) AS sum_of_matching_c4
FROM  (
  SELECT c4, array_agg(x ORDER BY x) AS arr
  FROM  (
      SELECT ctid, c4, unnest(ARRAY[c1,c2,c3]) AS x
      FROM   tbl t, i
      WHERE  ARRAY[c1,c2,c3] <@ arr -- optional pre-selection
      AND    ARRAY[c1,c2,c3] @> arr -- for better performance?
      ) a
   GROUP BY ctid, c4
   ) b
JOIN i USING (arr)

-> sqlfiddle デモ。

主な困難は、行内の列の値を順序付けすることです

入力 (3 つの文字列) については、すぐに注文して配列に収集するCTEの式をWHERE含む句でこれを実現します。ここでは便宜上 CTE を使用しているため、値を 1 か所だけ入力する必要があります。VALUE

行の値の場合はより複雑です。3 つの列を配列に入れ、それを で行に分割しunnest()ます。主キーを提供しなかったので、ctid代わりにアドホックの代理主キーを使用します。これGROUP BYは、現在ソート(c1, c2, c3)されているものを配列に詰め込むために必要です。

c4最後に、ソートされた配列が正確に一致するすべての行を合計します。

注: 明確な結果が得られないため、明示的に使用しませ。検討:string_agg()

'abc' 'cde' 'fgh'
'ab' 'ccdef' 'gh'

.. 連結された場合、結果は同じ文字列になります。

指数・性能

クエリを高速化するために、事前に並べ替えられたデータを保存することを検討してください。その場でそれを行うには費用がかかります。つまり、並べ替えられた配列を事前に生成し、それを冗長列として保存して、インデックスでサポートすることができます。冗長データ ストレージのコストに対して、桁違いに高速である必要があります。長い文字列
を扱っている場合は、dba.SE に関するこの関連する回答で概説したものと同様の解決策が最善の方法である可能性があります。

または、(推奨!)(c1, c2, c3)常に昇順で格納されることを保証します。トリガーBEFORE INSERT OR UPDATEを使用して、順序付けされた行内の値を保持できます。冗長なストレージはなく、3 つの列に複数列のインデックスを作成し、それらを 1 つずつ比較するだけです (私の例のように配列を比較する代わりに)。

于 2012-10-15T20:50:07.623 に答える
0

そのための関数を書く必要はありません。

まず、postgresql ( sql ) には「文字列」はなく、「テキスト」または「varchar」です。

次に、次のような SQL クエリが必要です。

SELECT ( DISTINCT ( c1 || c2 || c3 )) AS txtcol, SUM (c4) AS rowsum; 

また

SELECT ( DISTINCT ( c1 || c2 || c3 )) AS txtcol, SUM(c4) AS numsum GROUP BY txtcol;

現時点では正確な構文を思い出すことはできません。解決する必要があります。とにかく、CONCAT や "||" などの組み込み関数を使用して varchar 列を連結する必要があります。演算子、次に数値列による合計/グループ化。必要なのは、列を連結し、結果のすべてをまとめた列に名前を付けることだけです。正確には、結果のテーブルに連結された列を表示する必要さえありません。たとえば、合計と要約された行数だけを出力できます。

理論的には、そのためにSQL関数またはPL/SQL関数を書くことができますが、それは必要ではないと確信しています。あなたのケースは、関数なしで必要な結果を達成できるほど単純に思えます。組み込みの集計関数 SUM() は「集計」関数と呼ばれ、集計関数の他の例としては、MIN() や MAX() などがあります。実際に行おうとしていることは、行ごとの連結の効果によって、結果の VARCHAR 列によって行をグループ化することに注意してください。

EDIT:SQLまたは手続き型SQLの「配列」は、内部で処理される配列です。それらを関係(データベース内のテーブル、またはSELECT結果としてのテーブル)と混同しないでください。そのために SQL 配列も必要ないと思いますが、タスクは見た目ほど難しくありません。

于 2012-10-15T20:37:37.420 に答える