如何避免表连接上的无关数据

时间:2014-08-12 16:53:53

标签: sql sql-server

使用MSSQL 2012,我有三个表。表0有一个值,我用它来连接其他一些表,如下所示:

Table0

----------
keyval
1



Table1

----------
keyval   someval
1        blah
1        blah1


Table2

----------
keyval  someotherval
1       woo
1       woo1
1       woo2

现在,如果我执行以下查询

SELECT  Table1.someval AS val1, Table2.someotherval AS val2
FROM  Table0
INNER JOIN Table1 ON Table0.keyval = Table1.keyval
INNER JOIN Table2 ON Table0.keyval = Table2.keyval
WHERE Table0.keyval = '1'

我得到以下结果:

val1    val2

----------
blah    woo
blah    woo1
blah    woo2
blah1   woo
blah1   woo1
blah1   woo2

我的问题是,如何确保 每个值仅在结果中显示一次? 我想知道如何运行查询以获得以下结果

val1    val2

----------
blah    woo
blah1   woo1
null    woo2

我尝试了所有不同类型的连接,但效果不佳。我有一种感觉,我需要UNION某处,但我不知道在哪里

4 个答案:

答案 0 :(得分:1)

您似乎想要一个笛卡尔积的随机子集,其中每个值都表示一次,所以这样的事情应该这样做:

with t0(k) as ( 
  select 1 
), t1(k,v1) as (
  select 1,'blah' 
  union 
  select 1,'blah1'
), t2(k,v2) as ( 
  select 1,'woo'
  union
  select 1,'woo1'
  union
  select 1,'woo2'
), t3(k,v1,rn) as ( 
  select t1.k, v1, row_number() over (order by t1.v1) as rn1 
  from t1
  join t0
      on t0.k = t1.k
), t4(k,v2,rn) as (
  select t2.k, v2, row_number() over (order by t2.v2) as rn2 
  from t2
  join t0
      on t0.k = t2.k
) 
select t3.v1, t4.v2 
from t3 
full join t4 
    on t3.k = t4.k 
   and t3.rn = t4.rn


V1      V2
blah    woo
blah1   woo1
(null)  woo2

编辑:使用表而不是CTE t0,t1和t2

create table table0 (k int not null);
insert into table0 (k) select 1;
create table table1 (k int not null, v1 varchar(5) not null);
create table table2 (k int not null, v2 varchar(5) not null);
insert into table1 (k,v1)
select 1,'blah' 
union 
select 1,'blah1'
union
select 1, 'jojo'
union
select 1, 'jojo1';

insert into table2 (k,v2)
select 1,'woo'
union
select 1,'woo1'
union
select 1,'woo2';

with t3(k,v1,rn) as ( 
    select t1.k, v1, row_number() over (order by t1.v1) as rn1 
    from table1 t1
    join table0 t0
        on t0.k = t1.k
), t4(k,v2,rn) as (
   select t2.k, v2, row_number() over (order by t2.v2) as rn2 
   from table2 t2
   join table0 t0 
       on t0.k = t2.k
) 
select t3.v1, t4.v2 
from t3 
full join t4 
    on t3.k = t4.k
   and t3.rn = t4.rn;

V1      V2
blah    woo
blah1   woo1
jojo    woo2
jojo1   (null) 

delete from table1 where v1 like 'joj%';

with t3(k,v1,rn) as ( 
   select t1.k, v1, row_number() over (order by t1.v1) as rn1 
   from table1 t1
   join table0 t0
       on t0.k = t1.k
), t4(k,v2,rn) as (
   select t2.k, v2, row_number() over (order by t2.v2) as rn2 
   from table2 t2
   join table0 t0 
       on t0.k = t2.k
) 
select t3.v1, t4.v2 
from t3 
full join t4 
    on t3.k = t4.k 
   and t3.rn = t4.rn;

V1      V2
blah    woo
blah1   woo1
(null)  woo2

答案 1 :(得分:0)

我觉得将唯一值拉入单个列会容易得多, 然后使用第二个“假”'列,用于指定值的来源。 由于他们不一定要互相配对,因此没有理由将它们成对列出。

 SELECT DISTINCT Table1.someval AS val,'Table1' As source
 FROM Table1
 WHERE Table1.keyval = '1'
 UNION
 SELECT DISTINCT Table2.someval as val, 'Table2' As source
 FROM Table2
 WHERE Table2.keyval = '1'

请注意,在这种情况下,我完全删除了Table0,数据设置方式与问题相符,Table0唯一重要的时间是,如果没有keyval = 1 in Table0,在这种情况下,您将无法获得任何结果。

但是,如果这对你很重要,

 SELECT DISTINCT Table1.someval AS val,'Table1' As source
 FROM Table1
 INNER JOIN Table0 ON Table0.keyval = Table1.keyval
 WHERE Table0.keyval = '1'
 UNION
 SELECT DISTINCT Table2.someval as val, 'Table2' As source
 FROM Table2
 INNER JOIN Table0 ON Table0.keyval = Table2.keyval
 WHERE Table0.keyval = '1'

答案 2 :(得分:0)

基于给定的数据,我越接近:

select s.val1, s.val2
    from (
        select t1.someval as val1
                , null as val2
            from table1 t1
        union
        select null as val1
                , t2.someotherval as val2
            from table2 t2
    ) s

结果如下:

val1  | val2
--------------
blah  | (null)
blah1 | (null)
(null)| woo
(null)| woo1
(null)| woo2

请参阅SQL Fiddle

否则,你可以做到这一点:

  val
-------
 blah
 blah1
 woo
 woo1
 woo2

使用此查询:

select t1.someval as val
    from table1 t1
union
    select t2.someotherval 
        from table2 t2

请参阅SQL Fiddle

虽然两者都不是理想的结果集,但这是我能用给定输入得到的最接近的结果。

答案 3 :(得分:-2)

如果要查看已连接表格的NULL结果,请使用' LEFT JOIN'。

SELECT  Table1.someval AS val1, Table2.someotherval AS val2
FROM  Table0
LEFT JOIN Table1 ON Table0.keyval = Table1.keyval
LEFT JOIN Table2 ON Table0.keyval = Table2.keyval
WHERE Table0.keyval = '1'