web-dev-qa-db-ja.com

JSON配列のスライスから最大値を取得しますか?

Jsonオブジェクトのスライス内の最大値を取得したい(通常[1,2,3,5,6,7,9,10])テーブルDatarawというフィールドに含まれています。

スライスの制限StartEndは、Featuresという名前のテーブルに含まれるfeaturesという名前の他のJsonオブジェクトに含まれています

ここに入力があります:

CREATE TABLE raw (
    id     int PRIMARY KEY
      GENERATED BY DEFAULT AS IDENTITY

    data   json
);

INSERT INTO raw (data) VALUES
  ('[1,2,3,5,6,7,9,10]');

CREATE TABLE features (
    id         int,
    features   json
);

INSERT INTO features (id, features) VALUES
  (1, '{"Start" : 1, "End": 5}');

私が望む出力は7、つまりスライスの最大値[2,3,5,6,7]

これは私が他の投稿を見て思いついたものですが、うまくいきません...

SELECT
    R."ID",
    F."Features"->>'Start' AS Start, 
    F."Features"->>'End' AS End,
    sort_desc((array(select json_array_elements(R."Data")))[F."Features"->>'Start':F."Features"->>'End'])[1] as maxData
FROM 
    raw AS R
INNER JOIN 
    features AS F ON R."ID" = F."ID"

表示されるおおよそのエラーメッセージはsort_desc

この名前またはこのタイプの引数に対応する関数はありません。データのタイプを変換する必要があります

2
Maxime

Json配列のネストを解除できます:

Postgres WITH ORDINALITY

FROM句の関数の末尾にWITH ORDINALITYを付けると、bigint列が出力に追加されます。この列は、1から始まり、関数の出力の行ごとに1ずつ増加します。これは、unnest()などのセットを返す関数の場合に最も役立ちます。

Erwin Brandstetter のこの答えを見てください:

  SELECT
     r."ID",
     MAX(t.elem::int) MaxElem
  FROM   
      raw r
  JOIN
      features f
      ON f."ID" = r."ID"
  JOIN LATERAL
      json_array_elements_text(r."Data")
      WITH ORDINALITY AS t(elem, n) ON TRUE
  WHERE
      n >= (f."Features"->>'Start')::int + 1 
      AND 
      n <= (f."Features"->>'End')::int + 1
  GROUP BY
      r."ID";
 ID | maxelem 
-:| ------:
 1 | 7

db <> fiddle ここ

または、intarrayモジュールを使用する場合:

SELECT
    r."ID",
    (sort_desc(((ARRAY(SELECT json_array_elements_text(r."Data")))::int[])[(f."Features"->>'Start')::int + 1:(f."Features"->>'End')::int + 1]))[1]
FROM
    raw r
JOIN
    features f
    ON f."ID" = r."ID";

rextester ここ

4
McNets

これは恐ろしいスキーマの周りです。 (実際には)jsonを(jsonbと比較して)まったく使用しないでください。フィールドでクエリを実行する場合は、jsonbにする必要があります。あなたの場合、それはまだ悪い考えですが、おそらくSQL配列が必要です。

CREATE TABLE raw (
    raw_id   int  PRIMARY KEY
      GENERATED BY DEFAULT AS IDENTITY,
    data     int[]
);

INSERT INTO raw (data) VALUES ('{1,2,3,5,6,7,9,10}');

CREATE TABLE features (
    feature_id   int REFERENCES raw,
    low          smallint,
    high         smallint
);

INSERT INTO features ( feature_id, low, high ) VALUES ( 1, 1, 5 );

これで、次のようにクエリできますsqlは1ベースであることを覚えておいてください

SELECT max(unnest)
FROM raw
CROSS JOIN features AS f
CROSS JOIN LATERAL unnest(data[f.low:f.high]);

上記を最適化するため、intarrayモジュールも確認してください。

CREATE EXTENSION intarray;

SELECT max(unnest)
FROM raw
CROSS JOIN features AS f
CROSS JOIN LATERAL unnest(subarray(data,f.low,f.high-f.low+1))

配列の最後の要素だけが必要な場合は、これをさらに最適化できます。


これがGISの問題である場合は、おそらく間違っている可能性がありますが、少なくともこの方法は正気です

2
Evan Carroll