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

Sql 如何避免表联接上的无关数据,sql,sql-server,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

使用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,但我不确定在哪里

如果您希望看到来自联接表的空结果,请使用“左联接”

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'

我有一种感觉,将唯一值拉到一列中会容易得多, 然后使用第二个“dummy”列指定值的来源。 因为他们不一定要配对,所以没有理由把他们成对地列出来

 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唯一重要的时间是如果Table0中没有keyval=1,那么您将不会得到任何结果

但是,如果这对你很重要

 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'

您似乎想要笛卡尔乘积的一个随机子集,其中每个值都表示一次,因此类似这样的操作应该可以:

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

根据给定的数据,我得到的距离为:

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

否则,您可以实现以下目标:

  val
-------
 blah
 blah1
 woo
 woo1
 woo2
使用此查询:

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


虽然这两个结果集都不是所需的结果集,但这是我能从给定输入中得到的最接近的结果集。

查询如何知道blah与woo匹配而不是与woo1匹配?您需要添加列,以便在数据库中明确关系。。。因为所有的keyval都是一样的,这就是预期的行为……您是否只是尝试在val的最后一个字符上进行联接?似乎您希望查询找出返回的列中哪一个具有最明显的值(在本例中为val2),然后将val2的每个值与满足联接条件的任何尚未使用的val1值进行匹配,如果val1的所有值都已用尽,则可能使用null。本例中的SELECT DISTINCT将获取所有6行,因为每行中的值组合都是DISTINCTGIVEND DATA不适合所需的结果集。您需要一个额外的键来匹配特定于表1和表2关系的记录。否则,我看不出你如何能达到预期的结果。通常,当一个表中的数据与另一个表中的数据没有可能的相关性时,就会得到这样的结果集,因此会出现空值。您希望在哪里找到空值?表0、表1或表2?查看您提供的表中的数据,不会有空值,因为每个键都会找到一个匹配的Table0.keyval、Table1.keyval、Table2.keyval。是的,我一直认为这可能也是最好的方法。我将等待一点,看看是否有sql忍者有一些偷偷摸摸的解决方案在这里;否则我会把这个标记为answer@Lennart:您是否正在从db中提取数据?t0、t1和t2模拟了其queryhaha中的表不,我在web服务中使用的参数化存储过程中已经有了这些数据。它工作得很好,因为通过将参数和我需要的主表中的所有列放在t0中,我能够获得所有相关数据,而无需复制每行中的所有数据。此外,返回的最大行数等于其中一个“副表”中的最大行数。我有很多这样的“副表”,所以这为我节省了大量通过网络发送的数据。值得注意的是,使用CTE不会允许将其转换为MySQL解决方案,如果您必须使用MySQL中的数据复制此工作流,这可能不相关,但值得注意。此外,如果val1现在有这些值:blah,blah1,blah2,blah3,这个答案会发生什么变化。。。OP表示,在这个原因中,val2需要空值。这似乎需要大量的代码修改,您需要手动了解列的唯一条目,以及哪些列的基数最大。这使得可重用性差。