忽略singlets的内部联接

时间:2012-11-09 13:33:45

标签: sql tsql self-join

我必须在桌子上进行自我加入。我正在尝试返回几个列的列表,以查看在同一天(MM / DD / YYYY)执行了多少种类型的药物测试,其中至少进行了两次测试,其中至少有一次导致了结果代码为'UN'。

我正在加入其他表格以获取如下信息。问题是我不太明白如何排除某个结果行的人,他们在某一天确实有'UN'结果但当天没有任何其他测试。

查询结果(列)

County, DrugTestID, ID, Name, CollectionDate, DrugTestType, Results, Count(DrugTestType)

ID 12345有几行是正确的。但ID 12346是一行显示他们有count(1)的行结果。他们在这一天有“联合国”的结果,但那天他们没有进行任何其他测试。我想排除这个。

我尝试了以下查询

select  
    c.desc as 'County',
    dt.pid as 'PID',
    dt.id as 'DrugTestID',
    p.id as 'ID',
    bio.FullName as 'Participant',
    CONVERT(varchar, dt.CollectionDate, 101) as 'CollectionDate',       
    dtt.desc as 'Drug Test Type',
    dt.result as Result,
    COUNT(dt.dru_drug_test_type) as 'Count Of Test Type'
from    
    dbo.Test as dt with (nolock)
       join dbo.History as h on dt.pid = h.id 
       join dbo.Participant as p on h.pid = p.id
       join BioData as bio on bio.id = p.id
       join County as c with (nolock) on p.CountyCode = c.code
       join DrugTestType as dtt with (nolock) on dt.DrugTestType = dtt.code
       inner join 
          (
             select distinct 
                dt2.pid,
                CONVERT(varchar, dt2.CollectionDate, 101) as 'CollectionDate'
             from   
           dbo.DrugTest as dt2 with (nolock)
                   join dbo.History as h2 on dt2.pid = h2.id 
                   join dbo.Participant as p2 on h2.pid = p2.id
             where
                dt2.result = 'UN'
                and dt2.CollectionDate between '11-01-2011' and '10-31-2012'
                and p2.DrugCourtType = 'AD'
          ) as derived
            on dt.pid = derived.pid 
            and convert(varchar, dt.CollectionDate, 101) = convert(varchar, derived.CollectionDate, 101)
group by 
   c.desc, dt.pid, p.id, dt.id, bio.fullname, dt.CollectionDate, dtt.desc, dt.result
order by 
    c.desc ASC, Participant ASC, dt.CollectionDate ASC

2 个答案:

答案 0 :(得分:0)

这有点复杂,因为您的查询每个测试都有一个单独的行。您需要使用窗口/分析函数来获取所需的信息。这些允许您计算聚合函数,但是将值放在每一行上。

以下查询从您的查询开始。然后,它计算每个参与者每个日期的联合国结果数量和测试总数。它应用适当的过滤器来获得您想要的东西:

with base as (<your query here>)
select b.*
from (select b.*,
             sum(isUN) over (partition by Participant, CollectionDate) as NumUNs,
             count(*) over (partition by Partitipant, CollectionDate) as NumTests
      from (select b.*,
                  (case when result = 'UN' then 1 else 0 end) as IsUN
            from base
           ) b
     ) b
where NumUNs <> 1 or NumTests <> 1

如果没有with子句或窗口函数,您可以创建一个特别难看的查询来执行相同的操作:

select b.*
from (<your query>) b join
     (select Participant, CollectionDate, count(*) as NumTests,
             sum(case when result = 'UN' then 1 else 0 end) as NumUNs
      from (<your query>) b
      group by Participant, CollectionDate
     ) bsum
     on b.Participant = bsum.Participant and
        b.CollectionDate = bsum.CollectionDate
where NumUNs <> 1 or NumTests <> 1

答案 1 :(得分:0)

如果我理解了这个问题,那么此类查询的基本模式只是在您的联接中包含否定或排除条件。 I.E.,columnA匹配的自联接,但B列和C列不匹配:

select
  [columns]

from
  table t1
  join table t2 on (
    t1.NonPkId = t2.NonPkId
    and t1.PkId != t2.PkId
    and t1.category != t2.category
  )

如果条件更好,则将条件放在WHERE子句中:

select
  [columns]

from
  table t1
  join table t2 on (
    t1.NonPkId = t2.NonPkId
  )

where
    t1.PkId != t2.PkId
    and t1.category != t2.category

从自联接开始通常最容易,将其视为加入所有相关信息的“基表”:

select
  [columns]

from
  (select
    [columns]

  from
    table t1
    join table t2 on (
      t1.NonPkId = t2.NonPkId
    )

  where
      t1.PkId != t2.PkId
      and t1.category != t2.category
  ) bt

  join [othertable] on (<whatever>)
  join [othertable] on (<whatever>)
  join [othertable] on (<whatever>)

这可以让您专注于正确地进行自我加入,而不会受到其他表的干扰。