Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server:基于记录相关值的表联接_Sql_Sql Server_Tsql_Join_Inner Join - Fatal编程技术网

SQL Server:基于记录相关值的表联接

SQL Server:基于记录相关值的表联接,sql,sql-server,tsql,join,inner-join,Sql,Sql Server,Tsql,Join,Inner Join,我正在尝试执行一种一般类型的查询,我不确定如何用文字表达它,以便找到最佳实践和执行示例的讨论 下面是一个示例用例 我有一个客户表,其中包含客户信息和一个订单表。我想根据客户特征从订单中提取一部分记录,这些记录受客户表中作为数据包含的“最早”和“最晚”日期的限制。对于解决方案来说,我必须将查询结果限制在此日期范围内,这一范围因客户而异 客户 +------------+------------+----------+---------------------+-------------------

我正在尝试执行一种一般类型的查询,我不确定如何用文字表达它,以便找到最佳实践和执行示例的讨论

下面是一个示例用例

我有一个
客户
表,其中包含客户信息和一个
订单
表。我想根据客户特征从
订单
中提取一部分记录,这些记录受
客户
表中作为数据包含的“最早”和“最晚”日期的限制。对于解决方案来说,我必须将查询结果限制在此日期范围内,这一范围因客户而异

客户

+------------+------------+----------+---------------------+-------------------+
| CustomerID |  Location  | Industry | EarliestActiveOrder | LatestActiveOrder |
+------------+------------+----------+---------------------+-------------------+
|        001 | New York   | Finance  | 2017-11-03          | 2019-07-30        |
|        002 | California | Tech     | 2018-06-18          | 2019-09-22        |
|        003 | New York   | Finance  | 2015-09-30          | 2019-02-26        |
|        004 | California | Finance  | 2019-02-02          | 2019-08-15        |
|        005 | New York   | Finance  | 2017-10-19          | 2018-12-20        |
+------------+------------+----------+---------------------+-------------------+
+----------+------------+------------+---------+
| OrderID | CustomerID | StartDate  | Details |
+----------+------------+------------+---------+
|     5430 |        003 | 2015-06-30 |     ... |
|     5431 |        003 | 2016-03-31 |     ... |
|     5432 |        003 | 2018-09-30 |     ... |
|     5434 |        001 | 2018-11-05 |     ... |
|     5435 |        001 | 2019-10-11 |     ... |
订单

+------------+------------+----------+---------------------+-------------------+
| CustomerID |  Location  | Industry | EarliestActiveOrder | LatestActiveOrder |
+------------+------------+----------+---------------------+-------------------+
|        001 | New York   | Finance  | 2017-11-03          | 2019-07-30        |
|        002 | California | Tech     | 2018-06-18          | 2019-09-22        |
|        003 | New York   | Finance  | 2015-09-30          | 2019-02-26        |
|        004 | California | Finance  | 2019-02-02          | 2019-08-15        |
|        005 | New York   | Finance  | 2017-10-19          | 2018-12-20        |
+------------+------------+----------+---------------------+-------------------+
+----------+------------+------------+---------+
| OrderID | CustomerID | StartDate  | Details |
+----------+------------+------------+---------+
|     5430 |        003 | 2015-06-30 |     ... |
|     5431 |        003 | 2016-03-31 |     ... |
|     5432 |        003 | 2018-09-30 |     ... |
|     5434 |        001 | 2018-11-05 |     ... |
|     5435 |        001 | 2019-10-11 |     ... |
用文字表达的示例用例是:“给我纽约金融客户的所有有效订单”

理想的结果是从
orders
表返回
OrderID
543154325434
的完整记录


考虑到一个包含10^6条记录的
orders
表,构造此类查询的一般好方法是什么

select o.*
from orders o
inner join customers c 
    on  c.Customer_id = o.Customer_id
    and o.StartDate between c.EarliestActiveOrder  and c.LatestActiveOrder
    and c.Industry = 'Finance'
    and c.Location = 'New York'

此查询中的性能,请考虑以下索引:

orders(customer_id,  StartDate)
customers(Customer_id, Industry, Location, EarliestActiveOrder, LatestActiveOrder)

假设结果集是订单的一小部分(比如少于1%的订单,但1%用于说明),我会这样表述查询:

select o.*
from customers c join
     orders o
     on o.Customer_id = c.Customer_id and
        o.StartDate between c.EarliestActiveOrder  and c.LatestActiveOrder
where c.Location = 'New York' and c.industry = 'Finance';
索引策略很棘手。对于较小的结果集,您可能希望首先限制客户,然后查找匹配的订单。此方法建议在以下方面建立索引:

  • 客户(地点、行业、客户id、早期战术订单、后期战术订单)
  • 订单(客户id,起始日期)
如果有其他列用于筛选,则需要为它们创建单独的索引。例如,对于
行业
-仅过滤:

  • 客户(行业、客户id、早期战术订单、后期战术订单)
这可能会变得很麻烦

另一方面,如果您的结果集可能有大量的订单,那么扫描
订单
表可能会更有效率。您可以尝试依赖优化器。或者只需将查询措辞为:

select o.*
from orders o
where exists (select 1
              from customers c
              where o.Customer_id = c.Customer_id and
                    o.StartDate between c.EarliestActiveOrder  and c.LatestActiveOrder and
                    c.Location = 'New York' and c.industry = 'Finance'
             );
在这种情况下,您需要一个关于
客户(客户id)
的索引,但这可能已经是主键了,所以您可以。这样做的好处是,您不需要担心确切的筛选条件。缺点是对
订单
进行全表扫描(但不包括
加入
分组依据
、或
订单依据