0

私はこの配列を持っています:

1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,11:0,12:0,13:0,14:0,15:0,16:0
17:0,18:0,19:0,20:0,21:0,22:0,23:0,24:0,25:0,26:0,27:0,28:0,29:0,30:0,31:0,32:0,
49:0,33:0,34:0,35:0,36:0,37:0,38:0,39:0,40:0,41:0,42:0,43:0,44:0,45:0,46:0,47:0,
48:0,50:0,51:0,52:0,53:0,54:0,55:0,56:0,57:0,58:0,59:0,60:0,61:0,62:0,63:9,64:0,
65:0,66:0,67:0,68:0,69:0,70:0,71:0,72:0,73:0,74:0,75:0,76:0,77:0,78:0,79:0,80:0,
81:0,82:0,83:0,84:0,85:0,86:0,87:0,88:0,89:0,90:0,91:0,92:0,93:0,94:0,95:0,96:0,
97:0,98:0,99:0,100:0

*:0次の結果のみが得られるように、すべてのエントリを次のようにフィルタリングします。

63:9

私はそれをよりよく説明する必要があると思います:

usersフィールドを持つテーブルがありますuser_skill
このフィールドには、次のような文字列があります。次の1:0, 2:0, 3:0, 4:3, 5:8, 6:9, 7:0, 8:0, 9:0構文を使用します。skill_id:prio,skill_id:prio,skill_id:prio,skill_id:prio,...

users今、私はテーブルを次のようにテーブルに結合したいと思いskillsます:

SELECT skill_name
FROM users
inner join skills on skills.skill_id = ANY (string_to_array(regexp_replace(user_skill,':[0-9]*','','g'),',')::int[])
where user_id = 16
order by skill_name

それはうまくいきますskill_nameが、ユーザーが持っている場所だけを見たいですprio <> 0

4

1 に答える 1

1

適切な解決策

正規化に慣れ、これをテーブル間の適切な n:m 関係として実装し、テーブルusersskills追加の属性prioを追加することをお勧めしuser_skillます。完全なレシピは次のとおりです:
PostgreSQL で多対多の関係を実装する方法は?

次に、クエリは非常に単純になります。

SELECT s.skill_name
FROM   user_skill uk
JOIN   skills s USING (skill_id)
WHERE  uk.user_id = 16
AND    uk.prio <> 0
ORDER  BY s.skill_name;

インデックスでバックアップすることができ (またそうする必要があります)、現在持っているものよりも数桁高速になります。
ディスク上にさらにスペースが必要です。

ダークサイドの解決策

この不運な状況に閉じ込められている間、このクエリで自分自身を助けることができます. ただし、これは少なくとも Postgres バージョンを前提としています

SELECT s.skill_name
FROM  (
   SELECT split_part(us_item, ':', 1) AS skill_id
   FROM  (
      SELECT trim(unnest(string_to_array(user_skill, ','))) AS us_item
      FROM   users
      WHERE  user_id = 16      -- enter user_id here
      ) x
   WHERE  split_part(us_item, ':', 2) <> '0'
   ) u
JOIN   skills s USING (skill_id)
ORDER  BY 1;

例のデモ:

SELECT split_part(us_item, ':', 1) AS skill_id
FROM  (
   SELECT  trim(unnest(string_to_array(
'1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0,11:0,12:0,13:0,14:0,15:0,16:0,'
'17:0,18:0,19:0,20:0,21:0,22:0,23:0,24:0,25:0,26:0,27:0,28:0,29:0,30:0,31:0,32:0,'
'49:0,33:0,34:0,35:0,36:0,37:0,38:0,39:0,40:0,41:0,42:0,43:0,44:0,45:0,46:0,47:0,'
'48:0,50:0,51:0,52:0,53:0,54:0,55:0,56:0,57:0,58:0,59:0,60:0,61:0,62:0,63:9,64:0,'
'65:0,66:0,67:0,68:0,69:0,70:0,71:0,72:0,73:0,74:0,75:0,76:0,77:0,78:0,79:0,80:0,'
'81:0,82:0,83:0,84:0,85:0,86:0,87:0,88:0,89:0,90:0,91:0,92:0,93:0,94:0,95:0,96:0,'
'97:0,98:0,99:0,100:0', ','))) AS item
   ) x
WHERE  split_part(us_item, ':', 2) <> '0';

trim()あなたの例のように、先頭と末尾のスペースを扱います。しかし、それらはずさんな質問のアーティファクトにすぎない可能性があります。

行方不明を修正しました,
ところで、SQL 標準では、私が示すように文字列リテラルを入力できます。奇妙ですが、時々便利です。

于 2013-06-26T13:45:55.413 に答える