配列データに新しい要素を追加・削除する方法

このQ&Aのポイント
  • PostgreSQLの配列に要素を追加するには、UPDATE文を使用し、指定した配列に新しい要素を追加することができます。
  • PostgreSQLの配列から要素を削除するには、UPDATE文を使用し、指定した要素を配列から除去することができます。
  • 上記の例では、idが1のレコードのdata配列に「10」を追加し、idが2のレコードのdata配列から「6」を削除しました。
回答を見る
  • ベストアンサー

配列データに対する、要素の追加・削除方法

PostgreSQLの配列に対して、要素の追加及び削除を行いたいのですが、下記のような動作をさせるには、※1と※2で、どのようなSQLを実行すれば良いでしょうか? よろしくお願いいたします。 >>> CREATE TABLE test ( id integer, data integer[] ); INSERT INTO test VALUES (1, '{0,1,2,3,4}'); INSERT INTO test VALUES (2, '{5,6,7,8,9}'); SELECT * FROM test; id | data ----+------------- 1 | {0,1,2,3,4} 2 | {5,6,7,8,9} (2 rows) UPDATE test [data配列に10を追加] WHERE id = 1; /* ※1 */ UPDATE test [data配列から6を除去] WHERE id = 2; /* ※2 */ SELECT * FROM test; id | data ----+------------- 1 | {0,1,2,3,4,10} 2 | {5,7,8,9} (2 rows) <<<

質問者が選んだベストアンサー

  • ベストアンサー
noname#249320
noname#249320
回答No.1

PostgreSQL での配列は使ったことが無いのでちょっと調べてみました。 配列要素の追加は下記のように出来るようです。 UPDATE test SET data = array_append(data, 10); UPDATE test SET data = data || ARRAY[10] しかし, マニュアルに配列要素の削除についての項目が見当たりませんでした・・・。 結構検索してみたのですがどうにも見つけられず, 配列関数としてもサポートされていないようですし, もしかしたら無いのかも? ^^; # data - ARRAY[6] とかやってもだめでした。

参考URL:
http://sirius.itfrontier.co.jp/Powergres/product/doc/japanese20/functions-array.html
pe_daichan
質問者

お礼

array_appendという関数があったのですね。気づきませんでした。ありがとうございます^^ 除去の方は、やはり関数も無いようなので、CREATE FUNCTION に初挑戦してみました。 >>> CREATE FUNCTION array_strip(integer[], integer) RETURNS integer[] AS '  DECLARE   src ALIAS FOR $1;   val ALIAS FOR $2;   dst integer[] := ''{}'';   i integer;  BEGIN   FOR i IN array_lower(src,1) .. array_upper(src,1) LOOP    IF src[i] != val THEN     dst := array_append(dst, src[i]);    END IF;   END LOOP;   RETURN dst;  END; ' LANGUAGE 'plpgsql'; UPDATE test SET data = array_append(data, 10) WHERE id = 1; UPDATE test SET data = array_strip(data, 6) WHERE id = 2; <<< 以上のようになりましたが、もっと効率の良い方法、ありますかね…。

その他の回答 (1)

noname#249320
noname#249320
回答No.2

配列の要素を操作する関数が限られている以上, 配列の要素を全部サーチする以外に方法はないかと思います。 配列要素がそれなりに大きくなると負荷もあがりそうですし, 関数やプロシージャはデバッグが大変です ^^; DB側ではなくフロント側で配列を操作するか, 配列データを正規化して別テーブルに分けるかにしたほうがいいかもしれません。

関連するQ&A

  • 測定結果が決められた範囲内か判定するSQL文

    決められた範囲内に測定結果が入っているかを判定するSQL文(またはストアドプロシージャ)を PostgreSQL 14.0を使って作ろうとしていますが、正しい結果が得られません。 具体的には、ケーブル・テーブルとスペック・テーブルで一致するテスト項目同士(例えば、'Test_1'同士)だけを比較したいのですが、他のテスト項目も引っ掛けてしまいます。 あと、下記のwhere test_item = 'Test_1', 'Test_2', 'Test_3'の部分を select test_item from cable; から一つ一つ取り出してループで回して代入し、最終的には id | test_item | test ----+-----------+------ 1 | Test_1 | 1.5 2 | Test_1 | 1.8 2 | Test_2 | 2.5 という、まとまった出力を得たいのですが、その方法を教えていただけないでしょうか? 自作のテーブルとSQL文は以下になります: create table cable( id integer default 0 not null ,test_item varchar(30) not null ,test numeric(3, 1) ,primary key (id, test_item) ); insert into cable values(1, 'Test_1', 1.5); insert into cable values(1, 'Test_2', 4.5); insert into cable values(1, 'Test_3', 2.5); insert into cable values(2, 'Test_1', 1.8); insert into cable values(2, 'Test_2', 2.5); insert into cable values(3, 'Test_3', 2.5); create table spec( test_item varchar(30) not null , lower_spec numeric(3, 1) , upper_spec numeric(3, 1) , primary key(test_item) ); insert into spec values('Test_1', 1.0, 2.0); insert into spec values('Test_2', 2.0, 3.0); insert into spec values('Test_3', 3.0, 4.0); postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_1') and test > (select lower_spec from spec where test_item = 'Test_1'); id | test_item | test ----+-----------+------ 1 | Test_1 | 1.5 2 | Test_1 | 1.8 (2 行) postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_2') and test > (select lower_spec from spec where test_item = 'Test_2'); id | test_item | test ----+-----------+------ 1 | Test_3 | 2.5 ←'Test_3'なので引っ掛けたくない 2 | Test_2 | 2.5 3 | Test_3 | 2.5 ←'Test_3'なので引っ掛けたくない (3 行) postgres=# select * from cable c WHERE c.test_item = test_item and test < (select upper_spec from spec where test_item = 'Test_3') and test > (select lower_spec from spec where test_item = 'Test_3'); id | test_item | test ----+-----------+------ (0 行) 必要であれば補足します。 では、よろしくお願いします。

  • データ登録時、重複エラーを避けたい

    MYSQLのデータベースの、IDという項目が主キーのTESTというテーブルに、データをに登録する際、 既に主キーが同じデータがない場合に、という条件をつけたいのですが、 下のように書くと、エラーになってしまいます。 INSERT INTO TEST (ID, NAME) VALUES ('a', 'abc') WHERE NOT EXISTS (SELECT * FROM TEST WHERE ID = 'a'); どうしたらよいか教えてください。

    • ベストアンサー
    • MySQL
  • SQLの数値への単位について

    現在SQLをpaizaにて実行してるのですが ・highにcm wightにkgの単位の付け方 ・UPDATE DELETEが上手く実行されない の二点の修正方法が分からず、どなたか教えて頂けないでしょうか? 「ソースコード」 create table employees(height integer, weight integer); INSERT INTO employees(height, weight) VALUES(170, 50); INSERT INTO employees(height, weight) VALUES(180, 90); INSERT INTO employees(height, weight) VALUES(165, 70); SELECT height FROM employees; SELECT height AS tall FROM employees; UPDATE employees SET height ='171' WHERE weight ='170'; DELETE FROM employees WHERE height ='180'; 「実行結果」 height 170 180 165 tall 170 180 165

    • ベストアンサー
    • MySQL
  • ポスグレでの幾何学データ配列の使い方について質問です。

    ポスグレでの幾何学データ配列の使い方について質問です。 create table test_table1 (id serial, test_lseg lseg[]); insert into test_table1(test_lseg) values (ARRAY[lseg'((0,44),(0,88))',lseg'((1,44),(1,88))',lseg'((2,44),(2,88))',lseg'((3,44),(3,88))',lseg'((4,44),(4,88))',lseg'((5,44),(5,88))'] ); という感じのテーブルを作成し、test_lsegカラムのArray内にある線分に特定の座標が含まれているかを調べるような事をしたいのですが、ARRAY内の要素を検索する際の演算子を指定する方法がよく分かりません。とりあえず以下のようなSQL文では検索できないようです。 SELECT * from test_table1 WHERE test_lseg && ARRAY[lseg'((0,80),(0,80))']; SELECT * from test_table1 WHERE lseg'((0,80),(0,80))' && any (test_lseg); test_lsegカラムのArray内にある線分に特定の座標が含まれているかが分かり、出来ればIndexが張れるようなやり方がありましたらご教授ください。

  • 受け取ったIDに該当する物にデータをDBに格納

    $query = "select * from ki where id= '{$_GET['id']}'"; こんな風に受け取ったIDによって表示が変わるページなんですが、 $sql = 'INSERT INTO kise(gazou2) VALUES ("' . $output . '")'; だと、新たにフィールドを作ってデータを格納してしまいます。 例えば{$_GET['id']}で受け取ったIDに該当するフィールドに格納したい場合 $sql = 'INSERT INTO kise(gazou2) VALUES ("' . $output . '")'; をどう改変したら良いですか?? $sql = 'INSERT INTO kise({$_GET['id']}gazou2) VALUES ("' . $output . '")'; と力ずくでしてみましたがダメでした。

    • 締切済み
    • PHP
  • ある条件の最大値+1を初番するにはロックが必要ですか?

    以下のテーブルでcolumn毎に連番を振る場合、 テーブルロックが必要でしょうか? テーブル test id column 1 a 2 a 1 b 新規データ登録手順 1.トランザクション 2.select max(id)+1 from test where column = b for update 3.insert test into (id,column) values (selectで取得した値,b) 4.トランザクション終了 これで、column毎に登録されているIDの最大値+1で 重複せずにデータのINSERTが保障されるでしょうか?

    • ベストアンサー
    • MySQL
  • TO_NUMBERの結果は、カラムに追加できない?

    いつもお世話になっています。 TO_NUMBER実行時、結果はnumeric型で取得できると思うのですが、 その値をカラムに追加することはできるのでしょうか? insert into number2 values((select numberStr,TO_NUMBER (numberStr,'000.000') from number),'aaa'); 実行すると、 副問い合わせは1列のみを返さなければなりませんというErrorが生じます。 なのでwhere句を追加しましたが、結果は同じです。 実行したsqlは、 create table number ( count integer not null primary key, numberStr varchar(20) not null ); create table number2 ( no numeric not null primary key, numberS varchar(30) not null); insert into number values(5,'555.55000'); insert into number2 values((select numberStr,TO_NUMBER (numberStr,'000.000') from number where count=5),'aaa'); です。 宜しくお願いします。

  • MySQLでWHEN句のサブクエリ中にて

    MySQL ver.5.0.95です。 PHPからSQL文を作ってDBへインサートしているのですが 重複した値が合った場合はupdateするように書いています。 TBL1には |id   |string   |count 1    aaa    0 2    bbb    3 3    ccc    1 TBL2には |id2    |string2    |count2 1      aaa      0 2      bbb      2 3      ccc      1 実際はもう少し複雑ですが、こういう感じでデータが入ってるとします。 このとき、TBL1のそれぞれをインサート若しくはアップデートするのに TBL2の同一IDのものの、count2の状態によって場合分けしたく 同一IDのcount2が1以上なら変更しない、という風にするため以下のように書いたのですが insert into TBL1 values (1, "aaa", 3), (2, "bbb", 3), (3, "ccc", 3), (4, "ddd", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = values(id)) >=1 THEN count ELSE count + values(count) END; #1064 - You have an error in your SQL syntax;というエラーになって出来ません。 WHENの中のサブクエリで、where id2 = values(id) 恐らくこの文がダメなようです。 例えば決め撃ちで1つ1つ書くと通ります。 insert into TBL1 values(1, "aaa", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 1) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(2, "bbb", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 2) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(3, "ccc", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 3) >=1 THEN count ELSE count + values(count) END; insert into TBL1 values(4, "ddd", 3) on duplicate key update count = CASE WHEN (select count2 from TBL2 where id2 = 4) >=1 THEN count ELSE count + values(count) END; これをエラーになったような文に変えて1文にまとめたいのですが、無理でしょうか? あとそもそもこれをまとめたほうが速いと思ってそうしたいのですが、 変わらないのなら1文1文;でつなげて書くやり方でいこうと思っています。 まとめると速くなることはあるでしょうか?

    • ベストアンサー
    • MySQL
  • 入力値と外部キーをINSERTするには

    追加したいカラムが3つあるとしまして、そのうち2つはフォームからの入力値で、残り1つは別テーブルのIDをWHEREで引っ張ってきてINSERTしたい場合、INSERT...VALUES()とINSERT...SELECT構文を組み合わせないとダメかと思うのですが、組み合わせるとうまくいきません。2つの文に分けるしかないのでしょうか? やりたいことは下の感じのSQLです。が、解釈してくれません。 INSERT INTO room(A, B, C) VALUES (1, 2, SELECT other_table.id FROM other_table WHERE other_table.id = 1");

    • ベストアンサー
    • MySQL
  • 直近2年度連続で減少していない年度を抽出

    以下のテーブルの様に時系列が抜けているテーブルから直近2年度連続で減少していない年度を 抽出しようとしています。 /* year|sale --------- 1990|50 1992|50 1993|52 1994|55 1997|55 */ /* CREATE TABLE sales2 (year INTEGER NOT NULL , sale INTEGER NOT NULL , PRIMARY KEY (year)); INSERT INTO sales2 VALUES (1990, 50); INSERT INTO sales2 VALUES (1992, 50); INSERT INTO sales2 VALUES (1993, 52); INSERT INTO sales2 VALUES (1994, 55); INSERT INTO sales2 VALUES (1997, 55); */ 以下の記述で直近の年度までなら表示できているとは思うのですが2年連続となると やり方が思いつきません。誰かご教授いただけないでしょうか? select year,sale from sales2 s1 where sale >=(select sale from sales2 s2 where s2.year = (select max(year) from sales2 s3 where s1.year > s3.year)) order by year ;