【问题标题】:SQL query filter list within a list列表中的 SQL 查询过滤器列表
【发布时间】:2019-09-13 05:10:12
【问题描述】:

考虑一个带有 2 个表的数据库,如下所示。 CompanyIdDepartment 表中指向 Company 的外键。公司名称是唯一的,但部门名称不是。

表:Department

+-------+-----------+-----------+-------------------+
|   id  |   name    | CompanyId |       phone       |
+-------+-----------+-----------+-------------------+
|   1   |   Sales   |       1   |   214-444-1934    |
|   2   |   R&D     |       1   |   555-111-1834    |
|   3   |   Sales   |       2   |   214-222-1734    |
|   4   |   Finance |       2   |   817-333-1634    |
|   5   |   Sales   |       3   |   214-555-1434    |
+-------+-----------+-----------+-------------------+

表:Company

+-------+-----------+
|   id  |   name    |  
+-------+-----------+
|   1   |   Best1   |
|   2   |   NewTec  | 
|   3   |   JJA     |
+-------+-----------+

我有一个像下面这样的过滤器。当部门名称为 null(空)时,表示该公司的所有部门 id 都应包含在结果中,但当有列表时,它应仅包含列出的那些。

    [ {
        companyName: "Best1",
        departmentName: ["Sales", "R&D"]
      },
      {
        companyName: "NewTec",
        departmentName: ["Finance"]
      } ,
      {
        companyName: "JJA",
        departmentName: null
      } 
    }]

注意:过滤器是动态的(对 API 端点的请求),可能包括数千家公司和部门。

我想要一个 sql 查询来返回所有符合条件的部门 ID。对于此示例,结果将是“1,2,4,5”。 (返回除 NewTec 销售部门的 id (3) 之外的所有部门 id)

我正在寻找高效的 SQL 和/或 linq 查询来返回结果。 我可以遍历公司并为每个单独的部门过滤掉部门,但这意味着对于每个公司来说,将使用 ORM 访问一次数据库。有没有更好的办法来处理这种情况?

【问题讨论】:

  • 您要处理数量不定的条件。有两种方法可以解决这个问题: (1) 根据您的条件动态构建查询字符串。 (2) 将条件放在单独的表中并针对该表进行查询。

标签: sql sql-server linq


【解决方案1】:

这是您想要的 SQL 查询:

SELECT
    d.id
FROM Department d
INNER JOIN Company c
    ON d.CompanyId = c.id
WHERE
    (c.name = 'Best1' AND d.name IN ('Sales', 'R&D')) OR
    (c.name = 'NewTec' AND d.name = 'Finance') OR
    c.name = 'JJA';

Demo

【讨论】:

  • 该请求只是一个示例,可以有任意组合和数百个,不能硬编码。
  • @Fred 你认为你的问题和我的回答被否决是有原因的吗?
  • @Fred Jand:因为可能有一个或两个或三个或一千个条件,所以每次查询都会有所不同。 Tim 正在显示针对上述条件的查询。因此,您会看到如何构建查询。毕竟,查询只是发送到 DBMS 的字符串,因此请在您的编程语言中构建该字符串,以便最终得到 Tim 所展示的内容。
  • @Tim Biegeleisen,我不知道,过去几个小时我一直在尝试解决这个问题。我对数据进行了简化(和更改),但真正的问题是我找不到合适的解决方案。
  • @FredJand 如果您要问的是如何创建一个灵活的单一准备好的语句,它可以涵盖许多不同的参数组合,那么有一种方法可以做到这一点,但您的问题并没有说明这一点。
【解决方案2】:

您想要处理数量不定的条件。解决这个问题主要有两种方法:

  1. 根据您的条件动态构建查询字符串。
  2. 将条件放在单独的表中并针对该表进行查询。

使用这样的过滤表:

公司名称 |部门名称 -------------+---------------- 最佳1 |销售量 最佳1 |研发 新科技 |金融 JJA | (空值)

不变的 (!) 查询将是:

SELECT *
FROM Department d
INNER JOIN Company c ON d.CompanyId = c.id
WHERE EXISTS
(
  SELECT *
  FROM Filter f
  WHERE f.company_name = c.name
  AND (f.department_name = d.name OR f.department_name IS NULL)
);

这是一个演示:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=49ff15426776536acc6f5bd7f88aaf8f(我为此劫持了 Tim 的演示 :-)

这里有一个想法如何结合提到的两种方法:使过滤表成为一个临时视图,即将它放在WITH 子句中。但是为了保持查询不变,您可以从执行动态部分的存储过程中填充 WITH 子句。存储过程将读取包含条件的 XML 并从中选择行。因此,您可以让您的 ORM 调用此过程以获得您想要的结果。

这里有一个线程解释了如何在存储过程中从 XML 获取输入构建查询:Creating a query from XML input parameter in SQL Server stored procedure and verifying output

查询看起来像这样:

WITH Filter AS (SELECT company_name, department_name FROM dbm.GetMyFilterDataFromXml(@Xml))
SELECT *
FROM Department d
INNER JOIN Company c ON d.CompanyId = c.id
WHERE EXISTS
(
  SELECT *
  FROM Filter f
  WHERE f.company_name = c.name
  AND (f.department_name = d.name OR f.department_name IS NULL)
);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2011-12-22
    相关资源
    最近更新 更多