【问题标题】:SQL to only return table values found in array valuesSQL 仅返回在数组值中找到的表值
【发布时间】:2022-02-03 07:08:45
【问题描述】:

如果在数组中找到表值,SQL noob 会尝试返回 db 结果。我正在使用 Node JS 和 Postgres。

到目前为止,我可以弄清楚如何返回单个项目的结果:

SELECT * FROM table WHERE position(value in 'someval1')>0
// returns [{ id: 1, value: 'val1' }]

我不知道如何用数组替换上面的单个项目('someval1')。

示例

给定下表:

id value
1 val1
2 val2
3 val3

和数组: ['foo', 'someval1', 'anotherval2', 'bar']

我如何检查每个数组项中是否存在要返回的表“值”:

[
  { id: 1, value: 'val1' },
  { id: 2, value: 'val2' }
]

【问题讨论】:

  • 如果数组中的值包含包含表行值的字符串,您想从表中返回行吗?只是需要一些清晰。还是要返回包含字符串数组中的值的行?

标签: javascript sql node.js arrays postgresql


【解决方案1】:

这是倒退。通常你会做类似...

select * from theTable where searchField like '%text1%' or searchField like '%text2%'

但是当行的数据包含在条件数组中的多个值中时,您似乎试图从表中提取行。我认为您可能正在寻找的是temporary tables(尽管这种确切的语法可能很快就会被弃用,我目前看不到替代品)。您将创建一个临时表,其中只有一个字段,其中包含数组中的文本值。然后,您可以使用表连接来获取您正在尝试的行为。比如……

select dt.*, tt.SearchString  
from DataTable dt 
right join TempTable tt 
on tt.SearchString like '%'+dt.value+'%'

我没有通过任何类型的测试器运行它,但是通过正确的连接,它应该只包含临时表中匹配的行。假设我的代码中有拼写错误,请查看临时表(或替代表),然后查看 joins

编辑:我想我会提供更多关于临时表的内容,因为您提到了 SQL 新手。我想你会想要这样的代码......

create temporary table TempTable (searchString varchar(100));
insert into TempTable values 
    ('foo'), 
    ('someval1'), 
    ('anotherval2'), 
    ('bar');

当然,您在与真实表进行联接之前运行它。

【讨论】:

  • 感谢您的回答。我最终改变了我的方法,因为就像你提到的那样,这似乎倒退了。不过,在研究了临时表之后,我认为该解决方案会奏效。
  • 请在下面查看我的答案——它解决了我的问题,但最好能确认最佳实践等。
【解决方案2】:

好的,如果临时表不是一个选项,我想到了你可以使用的方法的轻微变化(这就是为什么我将这个单独的答案作为一个单独的答案,以防它最终为你工作。

创建一个专门用于包含数组值的普通表。如果多个用户可能同时运行此过程,您将需要一个 ID(会话 ID、用户 ID、可靠唯一的东西)以确保您只使用与该人相关的值。所以,你会想要一张这样的桌子......

create table SearchTerms (ID int not null AUTO_INCREMENT, sessionID varchar(25), searchTerm varchar(50));

然后,当您运行查询时,您会从插入开始加载术语...

insert into SearchTerms values
    ('0129205017_smith', 'foo'), 
    ('0129205017_smith', 'someval1'), 
    ('0129205017_smith', 'anotherval2'), 
    ('0129205017_smith', 'bar');

接下来,您运行看起来像...的实际查询

select dt.*, st.searchTerm 
from SearchTerms st 
left join DataTable dt 
  on st.searchTerm like '%'+dt.value+'%' 
where st.sessionID = '0129205017_smith';

然后你可能想要清理一下,这样搜索词表就不会被东西堵塞......

delete from SearchTerms where sessionID = '0129205017_smith';

【讨论】:

    【解决方案3】:

    您可以考虑使用正则表达式。它的性能略低于 LIKE,但除非您的数据集确实需要大量优化,否则您可能永远不会注意到。我还包括了一个替代方法,它使用一个值列表的连接和 LIKE 来产生相同的结果。看到这个小提琴。我已将版本设置为 postgres 14,因为您没有指定:

    https://dbfiddle.uk/?rdbms=postgres_14&fiddle=7062f6828a161c934c3e8ef96110dd05

    创建和插入:

    create table SearchTerms (ID serial primary key, sessionID varchar(25), searchTerm varchar(50));
    insert into SearchTerms (sessionID, searchTerm) values
    ('0129205017_smith', 'foo'), 
    ('0129205017_smith', 'someval1'), 
    ('0129205017_smith', 'anotherval2'), 
    ('0129205017_smith', 'bar');
    

    使用正则表达式(~)的解决方案:

    select * from searchTerms 
    where searchTerm ~ 'val1|val2';
    

    使用 LIKE 和连接到值列表的解决方案:

    select * from searchTerms s
    join (SELECT 'val1' as term UNION ALL SELECT 'val2' as term) v
    on s.searchTerm like concat('%', v.term, '%');
    

    我个人更喜欢正则表达式,因为它的灵活性和简洁性,而且我很少发现使用 LIKE 可以提供足够的性能改进来使用它来支持正则表达式。

    【讨论】:

    • 感谢您的回答。你的类似于@Kevin 的——标记他的正确,因为我喜欢临时表的概念。
    • 感谢您的支持。我确实采用了这里讨论的解决方案(包括临时表)并将它们放在 EXPLAIN 中,以显示引擎如何执行它们。 dbfiddle.uk/…
    • 感谢您的意见!我发布了一个解决我的问题并且看起来很简单的解决方案——第二双眼睛会很棒!
    • 嘿,我将该解决方案添加到小提琴中。我通常在 mySQL 中工作,所以取消嵌套数组并不是我的首要任务,但您可以查看说明计划。在 mySQL 8+ 中有类似的东西,您可以在其中使用 json 数组作为表。我在 postGres 文档中没有看到相同的功能,所以我没有在此添加:dbfiddle.uk/…
    • 但是,除非您有大量数据需要处理,否则您不太可能在使用这些解决方案时遇到真正的性能问题。最简单和最容易维护的可能是最好的,而且您的非嵌套查询非常简洁。
    【解决方案4】:

    稍作修改后,我想我找到了最适合我的解决方案,并且避免了创建临时表:

    SELECT value FROM table 
        JOIN UNNEST (array['foo', 'someval1', 'anotherval2', 'bar']) AS array_val
        ON array_val ~ value;
    

    有兴趣确认这是否确实比发布的答案更简单/更有效 - 或输入如何改进它!

    【讨论】:

    • 老实说,我不明白为什么该查询对您有用。波浪号对我来说是令人困惑的部分。我认为这是一个否定操作,而不是一个比较本身。我还认为您必须进行正确的连接,这样您就不会从主表中获取在 unnest 表中没有匹配项的值。但如果它有效......那么......我可能需要更新我对mySQL的知识。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 2021-10-19
    • 1970-01-01
    相关资源
    最近更新 更多