【问题标题】:Selecting by two parameters from table通过表中的两个参数进行选择
【发布时间】:2017-03-06 05:23:09
【问题描述】:

我有一个 HTML 表单,我可以在其中找到作者在 URL 地址中的一本书。

网址是这样的:http://mywebsite.com/books/?author=john+smith 它会检索我的书。

我的 SQL 如下所示:

SELECT 
  doc_documents.id doc_id, 
  doc_documents.projection_isbd doc_isbd
FROM 
  doc_documents 
  LEFT JOIN doc_document_authors ON doc_document_authors.document_id = doc_documents.id 
  LEFT JOIN usr_users ON usr_users.id = doc_document_authors.user_id 
WHERE 
  doc_documents.status = 'CONFIRMED' AND
  db_type = 'PDB' AND
  deleted = 'f' AND
  usr_users.title ilike $1
ORDER BY
  doc_documents.publish_date desc

$1 参数来自 PHP 脚本,我从 URL GET 参数中提取。

问题是我在哪里尝试查找 url 中有两个(或多个)作者的书籍,i。 e.:

http://mywebsite.com/books/?author=john+smith&author2=william+lother

我这样尝试了我的 sql:

SELECT 
      doc_documents.id doc_id, 
      doc_documents.projection_isbd doc_isbd
    FROM 
      doc_documents 
      LEFT JOIN doc_document_authors ON doc_document_authors.document_id = doc_documents.id 
      LEFT JOIN usr_users ON usr_users.id = doc_document_authors.user_id 
    WHERE 
      doc_documents.status = 'CONFIRMED' AND
      db_type = 'PDB' AND
      deleted = 'f' AND
      (usr_users.title ilike $1 AND
       usr_users.title ilike $2)
    ORDER BY
      doc_documents.publish_date desc

但它不会工作。 可以帮我写个sql吗?

【问题讨论】:

  • 它不起作用:是的,因为您希望单个用户的名称(标题)与 2 个(或更多)模式匹配;这不会发生(除非模式彼此有些相似)。您真正需要的是加入您的表(doc_document_authorsusr_users)与查询中的作者过滤器一样多次,然后搜索 WHERE usr_users1.title ilike $1 AND usr_users2.title ilike $2 AND ...
  • 试过这个,但它确实有效,我通过这个 SQL 完成了这个:[SELECT * FROM elaba.doc_documents LEFT JOIN elaba.doc_document_authors ON doc_document_authors.document_id = doc_documents.id LEFT JOIN elaba.usr_users as auth1 ON auth1.id = doc_document_authors.user_id LEFT JOIN elaba.usr_users as auth2 ON auth2.id = doc_document_authors.user_id LEFT JOIN elaba.usr_users as auth3 ON auth3.id = doc_document_authors.user_id WHERE doc_documents.status = 'CONFIRMED' AND db_type = ' PDB' AND deleted = 'f' AND (auth1.title ilike 'Jhon Smith' and auth2.title ilike 'John Doe')]
  • 您还需要多次加入doc_document_authors(您的查询仍然是针对同一作者的过滤器,但现在已多次加入)。
  • 谢谢,这个很有魅力,这正是我需要的

标签: php postgresql


【解决方案1】:

你可以这样试试吗?

SELECT 
  doc_documents.id doc_id, 
  doc_documents.projection_isbd doc_isbd
FROM 
  doc_documents 
  LEFT JOIN doc_document_authors ON doc_document_authors.document_id = doc_documents.id 
  LEFT JOIN usr_users ON usr_users.id = doc_document_authors.user_id 
WHERE 
  doc_documents.status = 'CONFIRMED' AND
  db_type = 'PDB' AND
  deleted = 'f' AND
  (usr_users.title ilike $1) OR
  (usr_users.title ilike $2)
ORDER BY
  doc_documents.publish_date desc

【讨论】:

  • 是的,我试过了,但事实并非如此,我想找到两个写得一样的作者。获取所有书籍,两位作者都在哪里写的。也可以有写三四位作者的书,只要输入网址,我就想得到那本书。
  • 您可以使用服务器端脚本语言来构建查询,然后您可以触发它。
【解决方案2】:

不应该

(usr_users.title ilike $1 OR usr_users.title ilike $2)

而不是

(usr_users.title ilike $1 AND usr_users.title ilike $2)

?

【讨论】:

  • 不,我想找两位作者写同一本书。作者数可以是 2 或 3。
【解决方案3】:

您期望单个用户的名称(标题)与 2 个(或更多)模式匹配;这不会发生(除非模式彼此有些相似)。

您需要做的(通常)是加入不同的用户(当然是不同的作者)并分别过滤它们:

SELECT    doc_documents.id doc_id,
          doc_documents.projection_isbd doc_isbd
FROM      doc_documents
JOIN      doc_document_authors author1 ON author1.document_id = doc_documents.id
JOIN      doc_document_authors author2 ON author2.document_id = doc_documents.id
JOIN      usr_users user1 ON user1.id = author1.user_id
JOIN      usr_users user2 ON user2.id = author2.user_id
WHERE     doc_documents.status = 'CONFIRMED'
AND       db_type = 'PDB'
AND       NOT deleted
AND       (user1.title ilike $1 AND user2.title ilike $2)
ORDER BY  doc_documents.publish_date desc

当您必须进行 N 次过滤时,这当然很难概括。

另一种可能性是在聚合中使用一些bool_or()

SELECT    doc_documents.id doc_id,
          doc_documents.projection_isbd doc_isbd
FROM      doc_documents
JOIN      doc_document_authors ON doc_document_authors.document_id = doc_documents.id
JOIN      usr_users ON usr_users.id = doc_document_authors.user_id
WHERE     doc_documents.status = 'CONFIRMED'
AND       db_type = 'PDB'
AND       NOT deleted
GROUP BY  doc_documents.id -- this will only work when id is the primary key
                           -- otherwise use the primary key of doc_documents
                           -- or doc_documents.*
HAVING    bool_or(usr_users.title ilike $1)
AND       bool_or(usr_users.title ilike $2)
ORDER BY  doc_documents.publish_date desc

这将确保每个 usr_users.title ilike $N 表达式将(至少 1 次)在每个文档的所有作者中为 true

还请注意,因为您在 WHERE 中过滤了 usr_users,所以使用 LEFT JOIN 毫无意义——无论如何,您的过滤器将强制使用 INNER JOIN(或简称为 JOIN)。

【讨论】:

  • 谢谢,我会尝试第二种解决方案,不过第一种很有效。
【解决方案4】:

不只是因为LIKEILIKE参数必须包含在%字符中以匹配字符串的一部分吗?您也可以尝试使用正则表达式匹配运算符~~*(用于不区分大小写的搜索),它不必使用% 来匹配

WHERE (usr_users.title ~* $1) AND (usr_users.title ~* $2)

注意:deleted 字段应该是 boolean 或 timestamptz 而不是无用的 char,这样 SQL 查询会变得更有表现力:

WHERE … AND NOT deleted AND …(布尔值)或WHERE … AND deleted_at IS NOT NULL AND …(时间戳)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-04
    • 2016-01-16
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多