【问题标题】:Can I make a join condition that joins if the join key has a particular field?如果连接键具有特定字段,我可以创建一个连接条件吗?
【发布时间】:2019-03-19 22:43:56
【问题描述】:

我有一个表格,其中有一列的字符串格式如下:{1,4,5}。它们可以是任意长度,我想针对在该字符串中具有其 ID 的任何值加入一个 ID 表。

这是第一张桌子

name     id         count 
apple    {1,3,6}    5
orange   {5,3,1}    3
potato   {8,1,9}    3

这是第二张桌子 -

id2     category
1      foo
2      foobar
3      candy
4      candybar
5      oreo
6      pistachio

我想为第一个表中列出的具有第二个表中的类别的每个 ID 设置一行。我希望它们看起来像这样 -

id2 name     id         count 
1 apple    {1,3,6}    5
1 orange   {5,3,1}    3
1 potato   {8,1,9}    3
3 apple    {1,3,6}    5
3 orange   {5,3,1}    3
8 potato   {8,1,9}    3
9 potato   {8,1,9}    3

这是我到目前为止所得到的。我可以有一个显示join if the value is included 的连接过滤器吗?

select id2, name, id, count
from table2 as t2 
left join table1 as t1 
on t2.id2 %in% t1.id

【问题讨论】:

  • 字符串函数因数据库而异。您使用的是什么特定的数据库? PostgreSQL、Oracle、DB2 等
  • 我正在使用 PostgreSQL。
  • 不管怎样,id 字段是从array_agg() 函数创建的,但我认为我应该将其转换为文本。

标签: sql postgresql


【解决方案1】:

1) 不请自来的建议

  • 我认为,如果您的数据库设计(即您切割表的方式)对您的事业真正有益,那么值得考虑。当前设置表的方式违反了 Codd 的数据库设计1st Normal Form。考虑更改您的设计以表达 FirstTableSecondTable 中的对象之间的 n:m 关系

  • 名称在表的上下文中有效。不要将id2 放在一个表中,将id 放在另一个表中,只需将两者都命名为id。在您的查询中,您可以将它们称为firsttable.idsecondtable.id 以区分它们。

2) 实际答案

是的,这是可能的,但(正如评论员所指出的)取决于您使用的数据库系统。

如果firststable.id 是 PostgreSQL 中的数组,则以下查询应该有效:

SELECT
    *
FROM
    first
JOIN
    second
ON
    second.id = ANY(first.ids);
    -- Took the liberty to change the column names   

SQLFiddle 提供了一个工作示例。

如果firsttable.id 是一个字符串,那么您可以使用 '{42, 23, 17}'::int[] 将字符串转换为数组,如here:

所述>
SELECT
    *
FROM
    first
JOIN
    second
ON
    second.id = ANY(first.ids::int[]);

这个SQLFiddle 给出了一个工作示例,以防它是一个字符串。

【讨论】:

  • 如果像 {1,2,3} 这样的值是整数数组,我会同意你的看法。但是,他们似乎是VARCHAR
  • 第二个 SQLFiddle 不能正确处理这个问题吗?
  • 我会调整答案以使其更加明确。
  • 我认为这行得通。 +1 的努力。我会鼓励你使用现代连接语法。
  • 谢谢!我不确定交叉加入或左加入是否更合适。您提出建议的原因是什么?提高可读性? :)
【解决方案2】:

我刚开始解决这个问题时没有看到 PostgreSQL。

您可以尝试以下方法,但不能保证 Postgre 不具备所有功能。

SELECT * FROM (
     SELECT 
         Split.a.value('.', 'VARCHAR(100)') AS ID2  
         ,A.Name, A.ID, A.[Count]
     FROM  
     (
         SELECT Name, [Count], ID,  
             CAST ('<M>' + REPLACE(REPLACE(REPLACE(ID,'{',''),'}',''), ',', '</M><M>') + '</M>' AS XML) AS Data  
         FROM [StackOver].[dbo].[SplitKey]
     ) AS A CROSS APPLY Data.nodes ('/M') AS Split(a)
 ) as B  
 Left Join [StackOver].[dbo].[SplitKeyID2] as C
 On B.ID2 = C.ID2
  Where C.Category > ''
 Order By B.ID2, B.name

【讨论】:

    【解决方案3】:

    我非常确信有一个更好的解决方案,它不涉及 GROUP BYARRAY_AGG(),但既然你已经在那里,我认为这个查询可能会对你有所帮助:

    select
      t2.id2,
      t2.category,
      t1.id,
      t1.count
    from table1 t1
    join table2 t2 on (
         position ('{' || t2.id2 || '}' in t1.id) <> 0
      or position ('{' || t2.id2 || ',' in t1.id) <> 0
      or position (',' || t2.id2 || ',' in t1.id) <> 0
      or position (',' || t2.id2 || '}' in t1.id) <> 0
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-05
      • 2016-11-13
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 2012-06-05
      相关资源
      最近更新 更多