質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

3回答

3829閲覧

bit計算されているテーブルのデータをSQLで検索したい

takichi

総合スコア11

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

2クリップ

投稿2018/05/24 00:57

編集2018/05/25 04:36

昔のプログラムの修正でとても困っています。

内容は以下のようなことなのですが、お知恵をお貸しいただけないでしょうか。

PostgreSQLに2つのテーブルAとBがあります。

Aのテーブルは、idとnameのカラムを持っており以下のような内容です。

CREATE TABLE A
(
id integer NOT NULL,
"name" text
)

テーブルA
|id|name|
|1|あああ|
|2|いいい|
|3|ううう|
|4|えええ|
|5|おおお|
|64|最大値|

idの最大値は64です。

Bのテーブルは、idとAのテーブルのidを計算をした値のカラムadを持っており以下のような内容です。

CREATE TABLE B
(
id integer NOT NULL,
bit bigint
)

テーブルB
|id|bit|
|1| 1 |
|2| 3 |
|3| 15 |
|4| 10 |
|5| 4 |

このBのテーブルにbitに入っている値ですが、Aのテーブルのidをbit?2進数?にしたものを計算して格納されています。

|id|bit| ← Aのテーブルのidを計算したもの
|1| 1 | ← あああ
|2| 3 | ← あああ、いいい
|3| 15 | ← あああ、いいい、ううう、えええ
|4| 10 | ← いいい、えええ
|5| 4 | ← ううう

Aのテーブルのidのごとの変換する値
|id|name|
|1|あああ| ← 1
|2|いいい| ← 2
|3|ううう| ← 4
|4|えええ| ← 8
|5|おおお| ← 16

やりたいことは、SQL文でAとBのテーブルを結合し、Bのテーブルのidが3の物を検索しAのテーブルのnameを求めたいのですが、何をどうしていいのかすらわかりません。

欲しい結果は、テーブルAのname が、

あああ、いいい、ううう、えええ

と、取得したいです。

SQL1文でやることはできませんでしょうか。

追記です。

テーブルAのidを64にするとpostgresqlの最大値を超えてしまうかとおもいます。

計算できれば計算したいですが、無理な場合は64の時は ”桁あふれ” などの
文字列を返したいです。

ご教授いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Orlofsky

2018/05/24 01:14 編集

PostgreSQL をタグに追加してください。 ビット列データ型を使っているのでしょうか?各テーブルの CREATE TABLE文も質問に追加してください。
takichi

2018/05/25 03:24

idの最大値を追記しました。
takichi

2018/05/25 04:05

Bテーブルのテーブル定義を変更しました。
guest

回答3

0

変換ルールは「2^A.ID-1」のようですので以下ではどうでしょうか。

SQL

1select b.*, a.NAME 2from テーブルB as b inner join テーブルA as a 3 on b.bit=2^(a.id-1) 4where b.id=3

追記

質問の意味を取り違えていたようです。
テーブルAに64bitのフラグごとのitemが登録されていて、それをテーブルBのIDの各フラグごとに対応させるということですね。

SQL

1select * 2 ,(select array_to_string(array_agg(name),',') from テーブルA where ((2^(id-1))::int & b.bit)>0) 3from テーブルB b 4where b.id=3

追記

array_aggをpostgres 8.1で展開

SQL

1select * 2 ,array_to_string(array( 3 select name from テーブルA 4 where ((2^(id-1))::bigint & b.bit)>0 5 ),',') 6from テーブルB b

尚、bigintだと2の62乗までしか展開できません。
また、ビット文字列演算子(&)は整数に対するものなのでbigintが上限です。
要は、テーブルAには63・64は登録できないということになります。

”桁あふれ”についてはそもそもbitに2の63乗以上は登録できないのですから、考慮は無意味だと思いますが。

投稿2018/05/24 01:18

編集2018/05/25 05:29
sazi

総合スコア25195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takichi

2018/05/24 01:51

ご回答ありがとうございます。 SQLを実行してみましたが、結果は0行でした。 select b.*, a.NAME from b inner join a on b.bit= 2 ^ (a.id-1) where b.id=3 SQLServerでも実行してみましたが、同様でした。 よろしくお願いいたします。
sazi

2018/05/24 01:57

以下を実行し変換ルールが正しいかどうか確認下さい。 select id, 2^(id-2) from テーブルa
takichi

2018/05/24 02:05

実行いたしました。 select id, 2^(id-2) from a id | 2^(id-2) ----+---- 1 | 0.5 ----+---- 2 | 1 ----+---- 3 | 2 ----+---- 4 | 4 ----+---- 5 | 8 このような結果になりました。 よろしくお願いいたします。
sazi

2018/05/24 02:07

ごめんないさい、確認内容の記述を間違えました。 select id, 2^(id-1) from テーブルa
takichi

2018/05/24 02:10

実行いたしました。 select id, 2^(id-1) from a id | 2^(id-1) ----+---- 1 | 1 ----+---- 2 | 2 ----+---- 3 | 4 ----+---- 4 | 8 ----+---- 5 | 16 このような結果になりました。 よろしくお願いいたします。
takichi

2018/05/24 04:21

ご回答ありがとうございます。 array_aggでエラーになってしまい、悩んだ結果 PostgerSQLのバージョンが古かったようです。 新しいバージョンで試したところ、望んでいる結果が得られました。 ありがとうございます。
sazi

2018/05/24 04:38

可読性だと、 ((2^(id-1))::int & b.bit)>0 より ((2^(id-1))::int & b.bit)::boolean=True とか ((2^(id-1))::int & b.bit)::boolean の方が良いかもしれない。
takichi

2018/05/24 05:05

ありがとうございます。 とても勉強になります。
takichi

2018/05/25 02:13

改めて質問をさせていただけますか。 他の方の回答にも書かせていただきましたが、Aのテーブルのidに64が入っているとエラーになってしまいます。 64だと桁あふれになるようなのですが、回避する方法はございませんでしょうか。 また、PostgerSQLのバージョンアップできない環境でSQLを実行しないと行けません。 array_aggを使用しない方法をご教授いただけますと幸いです。 よろしくお願いします。
sazi

2018/05/25 02:42

postgresのバージョンは何ですか?
takichi

2018/05/25 02:50

バージョンは8.1です。
sazi

2018/05/25 03:08

それから、上限に達している具体的なデータも質問に追記して下さい。 特にテーブルB。
takichi

2018/05/25 03:26

ありがとうございます。 上限に達しております、情報を記載しました。 今上限に達しているのは、テーブルAのidです。 テーブルBの情報も記載した方がよろしいでしょうか。 最大値の64を変換すると-9223372036854775808 となります。
sazi

2018/05/25 03:29

その値だと、テーブルBの定義ではbitはintegerですけどオーバーフローしません?
takichi

2018/05/25 04:06

ご指摘いただきました通りです。 テーブルBの定義を変更いたしました。 bitはbigintでした。
takichi

2018/05/25 04:37

質問の追記をいたしました。 よろしければお願いいたします。
takichi

2018/05/29 05:28 編集

ご回答ありがとうございます。 ご記入いただきました内容で実行することができました。 テーブルAの値を元に、テーブルBへデータを登録するのは JAVAのプログラムの方で行っています。 64の場合は、-9223372036854775808 で登録されていました。 どのようにデータが登録されているのか調べてみます。
sazi

2018/05/28 10:36 編集

postgresは配列が使えるので、bit列を配列に置き換えて管理したほうが、良い気がします。 配列型に直せないとしたら、,区切りの文字列にしてstring_to_array()で配列に変換してアクセスする。 unnest()と組み合わせれば、bit演算も不要ですし。
takichi

2018/05/29 05:30

ご回答ありがとうございます。 DBのテーブル変更が出来るタイミングが来ましたら、配列や区切りの文字列に置き換える提案をしたいと思います。 私も今回このような計算をしているプログラムを初めてみましたので、どうしていいのかわからず質問させていただきました。 ご回答をいただきましてありがとうございました。
sazi

2018/05/29 06:03

同時にPostgresのバージョンアップも提案されては如何ですか? 互換性において特に問題は無いと思いますので。
takichi

2018/05/30 01:37

ありがとうございます。 バージョンアップも同時に行うようにいたします。
guest

0

ベストアンサー

こういうこと?1行にまとめたいとかならぜんぜん違うけど…

sql

1create table test ( 2 id int primary key, 3 n text 4); 5 6insert into test(id,n) 7select 1,'あああ'; 8insert into test(id,n) 9select 2,'いいい'; 10insert into test(id,n) 11select 3,'ううう'; 12insert into test(id,n) 13select 4,'えええ'; 14insert into test(id,n) 15select 5,'おおお'; 16 17create table testbit ( 18 id1 int primary key, 19 b int 20); 21 22insert into testbit(id1,b) 23select 1,1; 24insert into testbit(id1,b) 25select 2,3; 26insert into testbit(id1,b) 27select 3,10; 28insert into testbit(id1,b) 29select 4,15; 30insert into testbit(id1,b) 31select 5,4; 32 33 34select b.*,a.n 35from testbit as b 36 inner join ( 37select a.*,cast(2^(a.id-1) as int) as b 38from test as a 39 ) as a on b.b & a.b > 0

投稿2018/05/24 01:56

sousuke

総合スコア3828

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takichi

2018/05/24 02:23

ご回答ありがとうございます。 そういうことです。 select b.*,a.n from testbit as b inner join ( select a.*,cast(2^(a.id-1) as int) as b from test as a ) as a on b.b & a.b > 0 where b.id1=4 こちらで欲しい検索結果を得ることができました。 ありがとうございます。
takichi

2018/05/24 07:29 編集

もう一度お知恵をお貸しいただけませんでしょうか。 create table test ( id int primary key, n text ); insert into test(id,n) select 64,'最大値'; testのテーブルに、64の値が入っていると以下のエラーになります。 ERROR: integer out of range select a.*,cast(2^(a.id-1) as int) as b こちらを select a.*,cast(2^(a.id-1) as bigint) as b このように変更してもエラーになります。 ERROR: bigint out of range 64は桁あふれを起こしてしまっているようです。 計算できれば計算したいですが、無理な場合は64の時は ”桁あふれ” などの 文字列を返したいです。 ご教授いただけませんでしょうか。 よろしくお願いいたします。
sousuke

2018/05/28 02:52 編集

すみません気づくのが遅れました。最大値は64としbigintでマイナス反転して管理されては select a.*,cast((case when a.id = 64 then -2 else 2 end)^(a.id-1) as bigint) as b from test as a
takichi

2018/05/28 08:43 編集

ご回答ありがとうございます。 こちらに変更して実行して見ました。 エラーは出なくなりました。 a.id が 64 の時の値「最大値」は取得することができませんでした。 64の時の値は取得できないものなのでしょうか。 よろしくお願いいたします。
sousuke

2018/05/28 09:17

マイナスを取らないままにしているのでは? ) as a on b.b & a.b <> 0 感覚的には取れるはずですが…テストしてはいないのでご了承。
takichi

2018/05/28 10:13

ご回答ありがとうございます。 記載の通り修正したところ、取得することができました。 ありがとうございます。
guest

0

ベタな書き方しかできませんでした…。
ONの条件を汎用的に1行で書けるとよいのですが、そこまでの知恵がありませんでした。
しかしビットということなので上限は決まっているでしょうから、条件を羅列してもたかがしれているかもしれません。
いや、最大で64行とかだときついか…。

SQL

1select B.id, A.name from B 2 left join A on ( 3 A.id = (case when (B.bit & 1) != 0 then 1 else null end) OR 4 A.id = (case when (B.bit & 2) != 0 then 2 else null end) OR 5 A.id = (case when (B.bit & 4) != 0 then 3 else null end) OR 6 A.id = (case when (B.bit & 8) != 0 then 4 else null end) OR 7 A.id = (case when (B.bit & 16) != 0 then 5 else null end) 8 );

else nullは不要かもしれませんが、一応入れています。

投稿2018/05/24 01:33

ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takichi

2018/05/24 01:57

ご回答ありがとうございます。 実行してみたところ、望んでいる結果が得られました。 select B.id, A.name from B left join A on ( A.id = (case when (B.bit & 1) != 0 then 1 else null end) OR A.id = (case when (B.bit & 2) != 0 then 2 else null end) OR A.id = (case when (B.bit & 4) != 0 then 3 else null end) OR A.id = (case when (B.bit & 8) != 0 then 4 else null end) OR A.id = (case when (B.bit & 16) != 0 then 5 else null end) ) where B.id=3 ; お察しの通り、実際のデータは64まであります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問