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 关系以及表users中的skills附加属性。这是一个完整的秘诀:如何在 PostgreSQL 中实现多对多关系?priouser_skill

那么你的查询可以很简单:

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 回答