为什么子查询不会创建重复的结果?

时间:2018-12-22 07:06:51

标签: sql sql-server tsql

我知道使用联接如何创建重复值。因此,我们需要在联接语句中使用DISTINCT关键字。但是,为什么使用子查询也不会给出重复的值?考虑以下对产生相同结果的T-SQL语句

子查询

import { Component, OnInit } from '@angular/core';

import { Controls } from '../main/main.component';

@Component({
  selector: 'app-generator',
  templateUrl: './generator.component.html',
  styleUrls: ['./generator.component.scss']
})
export class GeneratorComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  /**
   * name
   */
  public generateNewControl(controlType:string):string {
    console.log('new control generated');
    switch(controlType){
      case 'text':
        return this.renderTextBox();
      break;
    }
  }

  renderTextBox():string{
    return '<mat-form-field class="example-full-width"><input matInput 
           placeholder="Favorite food" value="Sushi"></mat-form-field>'
  }

  generateTextBox():void{
  var d = document.getElementById('main');
    d.insertAdjacentHTML('beforeend', 
    this.generator.generateNewControl('text'));
  }
}

加入

 select ID, Name, Description
    from tblProducts
    where ID IN
    (
      Select ProductId from tblProductSales
    )

我们必须对表联接使用distinct关键字,但对于子查询则不能使用。我不明白为什么会这样

2 个答案:

答案 0 :(得分:0)

在第一个查询上,您扫描产品表并检查该产品是否有任何销售。之所以这样,是因为每种产品仅出现一次,没有重复。 IN是布尔运算符,因此,即使子查询返回重复结果,也仅在与这些值中的任何一个匹配时才返回一行。

在第二个查询中,将每个产品与ID相匹配的任何销售合并。之所以这样,是因为同一产品有多次销售,因此您会重复购买。

在两个表之间加入一个笛卡尔积。

示例:

 Pruducts       Sales
    1             1
    2             1
    3             2
                  2
                  2

第一个查询返回(1,2)

第二条查询返回(1,1,2,2,2),因为产品中的每一行都试图与销售中的一行相匹配

答案 1 :(得分:0)

您误解了WHEREJOIN

由于非常简单的原因,第一个查询不会产生重复的结果。 WHERE子句从结果集中过滤掉行或将其保留在里面。仅此而已。由于WHERE条件,行不可能“相乘”。

从概念上讲,您可以将WHERE处理为:

  • 读取由FROM子句生成的行。
  • WHERE子句中应用条件。
  • 如果条件评估为TRUE,则继续处理该行。
  • 如果条件评估为FALSE或NULL,则删除该行。

JOIN完全是另一种野兽。它是FROM子句中的 operator ,它组合了两个表/派生表。可以删除行(当JOIN条件不等于TRUE时)。行可以相乘(如果有多个匹配项)。

顺便说一句,第一种方法比第二种方法要好得多。 SELECT DISTINCT会产生开销-即使所有行都已经不同。第二种方法不需要这样做。

我通常建议使用EXISTS编写此逻辑:

select p.ID, p.Name, p.Description
from tblProducts p
where exists (select 1
              from tblProductSales ps
              where ps.ProductId = p.ID
             );

我发现EXISTS通常更易于优化,并且NOT EXISTSNOT IN更可取,因为NOT EXISTS处理NULL的值符合您的期望(但是那是另一个主题)。